diff --git a/.cproject b/.cproject
deleted file mode 100644
index 73bc743d..00000000
--- a/.cproject
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.gitignore b/.gitignore
index 881e3650..33aec96e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
-bin/*
-gen/*
-obj/*
+*/bin/*
+*/gen/*
+*/obj/*
+*.o
+*.class
diff --git a/src/org/oscim/backend/BitmapUtils.java b/src/org/oscim/backend/BitmapUtils.java
deleted file mode 100644
index 6a952cd6..00000000
--- a/src/org/oscim/backend/BitmapUtils.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2010, 2011, 2012 mapsforge.org
- *
- * This program is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along with
- * this program. If not, see .
- */
-package org.oscim.backend;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.oscim.backend.canvas.Bitmap;
-
-
-public final class BitmapUtils {
- private static final String PREFIX_FILE = "file:";
- private static final String PREFIX_JAR = "jar:";
-
- private static InputStream createInputStream(String src) throws FileNotFoundException {
- if (src.startsWith(PREFIX_JAR)) {
- String name = "/org/oscim/theme/styles/" + src.substring(PREFIX_JAR.length());
-
- InputStream inputStream = BitmapUtils.class.getResourceAsStream(name);
- if (inputStream == null) {
- throw new FileNotFoundException("resource not found: " + src + " " + name);
- }
- return inputStream;
- } else if (src.startsWith(PREFIX_FILE)) {
- File file = new File(src.substring(PREFIX_FILE.length()));
- if (!file.exists()) {
- throw new IllegalArgumentException("file does not exist: " + src);
- } else if (!file.isFile()) {
- throw new IllegalArgumentException("not a file: " + src);
- } else if (!file.canRead()) {
- throw new IllegalArgumentException("cannot read file: " + src);
- }
- return new FileInputStream(file);
- }
- throw new IllegalArgumentException("invalid bitmap source: " + src);
- }
-
- public static Bitmap createBitmap(String src) throws IOException {
- if (src == null || src.length() == 0) {
- // no image source defined
- return null;
- }
-
- InputStream inputStream = createInputStream(src);
- Bitmap bitmap = CanvasAdapter.g.decodeBitmap(inputStream);
- inputStream.close();
- return bitmap;
- }
-
-
-
- private BitmapUtils() {
- throw new IllegalStateException();
- }
-}
diff --git a/vtm-android/.classpath b/vtm-android/.classpath
new file mode 100755
index 00000000..ab548081
--- /dev/null
+++ b/vtm-android/.classpath
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder.launch b/vtm-android/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder.launch
similarity index 100%
rename from .externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder.launch
rename to vtm-android/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder.launch
diff --git a/vtm-android/.project b/vtm-android/.project
new file mode 100755
index 00000000..205b4f13
--- /dev/null
+++ b/vtm-android/.project
@@ -0,0 +1,34 @@
+
+
+ vtm-android
+
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.settings/de.loskutov.anyedit.AnyEditTools.prefs b/vtm-android/.settings/de.loskutov.anyedit.AnyEditTools.prefs
similarity index 100%
rename from .settings/de.loskutov.anyedit.AnyEditTools.prefs
rename to vtm-android/.settings/de.loskutov.anyedit.AnyEditTools.prefs
diff --git a/vtm-android/.settings/edu.umd.cs.findbugs.core.prefs b/vtm-android/.settings/edu.umd.cs.findbugs.core.prefs
new file mode 100644
index 00000000..a374267c
--- /dev/null
+++ b/vtm-android/.settings/edu.umd.cs.findbugs.core.prefs
@@ -0,0 +1,132 @@
+#FindBugs User Preferences
+#Fri Oct 12 01:06:57 CEST 2012
+cloud_id=edu.umd.cs.findbugs.cloud.doNothingCloud
+detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true
+detectorAtomicityProblem=AtomicityProblem|true
+detectorBadAppletConstructor=BadAppletConstructor|false
+detectorBadResultSetAccess=BadResultSetAccess|true
+detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
+detectorBadUseOfReturnValue=BadUseOfReturnValue|true
+detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
+detectorBooleanReturnNull=BooleanReturnNull|true
+detectorCallToUnsupportedMethod=CallToUnsupportedMethod|false
+detectorCheckExpectedWarnings=CheckExpectedWarnings|false
+detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
+detectorCheckTypeQualifiers=CheckTypeQualifiers|true
+detectorCloneIdiom=CloneIdiom|true
+detectorComparatorIdiom=ComparatorIdiom|true
+detectorConfusedInheritance=ConfusedInheritance|true
+detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
+detectorCrossSiteScripting=CrossSiteScripting|true
+detectorDefaultEncodingDetector=DefaultEncodingDetector|true
+detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
+detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
+detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true
+detectorDontUseEnum=DontUseEnum|true
+detectorDroppedException=DroppedException|true
+detectorDumbMethodInvocations=DumbMethodInvocations|true
+detectorDumbMethods=DumbMethods|true
+detectorDuplicateBranches=DuplicateBranches|true
+detectorEmptyZipFileEntry=EmptyZipFileEntry|true
+detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true
+detectorExplicitSerialization=ExplicitSerialization|true
+detectorFinalizerNullsFields=FinalizerNullsFields|true
+detectorFindBadCast2=FindBadCast2|true
+detectorFindBadForLoop=FindBadForLoop|true
+detectorFindCircularDependencies=FindCircularDependencies|false
+detectorFindDeadLocalStores=FindDeadLocalStores|true
+detectorFindDoubleCheck=FindDoubleCheck|true
+detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
+detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
+detectorFindFinalizeInvocations=FindFinalizeInvocations|true
+detectorFindFloatEquality=FindFloatEquality|true
+detectorFindHEmismatch=FindHEmismatch|true
+detectorFindInconsistentSync2=FindInconsistentSync2|true
+detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
+detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
+detectorFindMaskedFields=FindMaskedFields|true
+detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
+detectorFindNakedNotify=FindNakedNotify|true
+detectorFindNonShortCircuit=FindNonShortCircuit|true
+detectorFindNullDeref=FindNullDeref|true
+detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true
+detectorFindOpenStream=FindOpenStream|true
+detectorFindPuzzlers=FindPuzzlers|true
+detectorFindRefComparison=FindRefComparison|true
+detectorFindReturnRef=FindReturnRef|true
+detectorFindRunInvocations=FindRunInvocations|true
+detectorFindSelfComparison=FindSelfComparison|true
+detectorFindSelfComparison2=FindSelfComparison2|true
+detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
+detectorFindSpinLoop=FindSpinLoop|true
+detectorFindSqlInjection=FindSqlInjection|true
+detectorFindTwoLockWait=FindTwoLockWait|true
+detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
+detectorFindUnconditionalWait=FindUnconditionalWait|true
+detectorFindUninitializedGet=FindUninitializedGet|true
+detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
+detectorFindUnreleasedLock=FindUnreleasedLock|true
+detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true
+detectorFindUnsyncGet=FindUnsyncGet|true
+detectorFindUseOfNonSerializableValue=FindUseOfNonSerializableValue|true
+detectorFindUselessControlFlow=FindUselessControlFlow|true
+detectorFormatStringChecker=FormatStringChecker|true
+detectorHugeSharedStringConstants=HugeSharedStringConstants|true
+detectorIDivResultCastToDouble=IDivResultCastToDouble|true
+detectorIncompatMask=IncompatMask|true
+detectorInconsistentAnnotations=InconsistentAnnotations|true
+detectorInefficientMemberAccess=InefficientMemberAccess|false
+detectorInefficientToArray=InefficientToArray|true
+detectorInfiniteLoop=InfiniteLoop|true
+detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
+detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
+detectorInitializationChain=InitializationChain|true
+detectorInitializeNonnullFieldsInConstructor=InitializeNonnullFieldsInConstructor|true
+detectorInstantiateStaticClass=InstantiateStaticClass|true
+detectorIntCast2LongAsInstant=IntCast2LongAsInstant|true
+detectorInvalidJUnitTest=InvalidJUnitTest|true
+detectorIteratorIdioms=IteratorIdioms|true
+detectorLazyInit=LazyInit|true
+detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
+detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true
+detectorMethodReturnCheck=MethodReturnCheck|true
+detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
+detectorMutableLock=MutableLock|true
+detectorMutableStaticFields=MutableStaticFields|true
+detectorNaming=Naming|true
+detectorNoteUnconditionalParamDerefs=NoteUnconditionalParamDerefs|true
+detectorNumberConstructor=NumberConstructor|true
+detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true
+detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
+detectorPublicSemaphores=PublicSemaphores|false
+detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
+detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true
+detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
+detectorRedundantInterfaces=RedundantInterfaces|true
+detectorRepeatedConditionals=RepeatedConditionals|true
+detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
+detectorSerializableIdiom=SerializableIdiom|true
+detectorStartInConstructor=StartInConstructor|true
+detectorStaticCalendarDetector=StaticCalendarDetector|true
+detectorStringConcatenation=StringConcatenation|true
+detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
+detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
+detectorSwitchFallthrough=SwitchFallthrough|true
+detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true
+detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true
+detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true
+detectorURLProblems=URLProblems|true
+detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
+detectorUnnecessaryMath=UnnecessaryMath|true
+detectorUnreadFields=UnreadFields|true
+detectorUselessSubclassMethod=UselessSubclassMethod|false
+detectorVarArgsProblems=VarArgsProblems|true
+detectorVolatileUsage=VolatileUsage|true
+detectorWaitInLoop=WaitInLoop|true
+detectorWrongMapIterator=WrongMapIterator|true
+detectorXMLFactoryBypass=XMLFactoryBypass|true
+detector_threshold=2
+effort=max
+filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,MT_CORRECTNESS,PERFORMANCE,STYLE|false|15
+filter_settings_neg=MALICIOUS_CODE,NOISE,I18N,SECURITY,EXPERIMENTAL|
+run_at_full_build=false
diff --git a/vtm-android/.settings/org.eclipse.cdt.codan.core.prefs b/vtm-android/.settings/org.eclipse.cdt.codan.core.prefs
new file mode 100644
index 00000000..0710d384
--- /dev/null
+++ b/vtm-android/.settings/org.eclipse.cdt.codan.core.prefs
@@ -0,0 +1,65 @@
+eclipse.preferences.version=1
+org.eclipse.cdt.codan.checkers.errnoreturn=Warning
+org.eclipse.cdt.codan.checkers.errnoreturn.params={implicit\=>false}
+org.eclipse.cdt.codan.checkers.errreturnvalue=Error
+org.eclipse.cdt.codan.checkers.errreturnvalue.params={}
+org.eclipse.cdt.codan.checkers.noreturn=Error
+org.eclipse.cdt.codan.checkers.noreturn.params={implicit\=>false}
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false}
+org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
+org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={unknown\=>false,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={paramNot\=>false}
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={else\=>false,afterelse\=>false}
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={macro\=>true,exceptions\=>("@(\#)","$Id")}
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
diff --git a/vtm-android/.settings/org.eclipse.core.resources.prefs b/vtm-android/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..e616f500
--- /dev/null
+++ b/vtm-android/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Sat Dec 17 10:00:00 CET 2011
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/vtm-android/.settings/org.eclipse.core.runtime.prefs b/vtm-android/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000..db872193
--- /dev/null
+++ b/vtm-android/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Sat Dec 17 10:00:00 CET 2011
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/vtm-android/.settings/org.eclipse.jdt.core.prefs b/vtm-android/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 00000000..f8801d84
--- /dev/null
+++ b/vtm-android/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,376 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=warning
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=ignore
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=warning
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=disabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=false
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/vtm-android/.settings/org.eclipse.jdt.ui.prefs b/vtm-android/.settings/org.eclipse.jdt.ui.prefs
new file mode 100755
index 00000000..5bdeaf3d
--- /dev/null
+++ b/vtm-android/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,115 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_blocks=false
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=_eclipse-cs VectorTileMap
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_vtm
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=/**\n * @return the ${bare_field_name}\n *//**\n * @param ${param} the ${bare_field_name} to set\n *//**\n * ${tags}\n *//**\n * \n *//**\n * @author ${user}\n *\n * ${tags}\n *//**\n * \n *//**\n * ${tags}\n *//* (non-Javadoc)\n * ${see_to_overridden}\n *//**\n * ${tags}\n * ${see_to_target}\n *//*\n * Copyright 2013 \n *\n * This program is free software\: you can redistribute it and/or modify it under the\n * terms of the GNU Lesser General Public License as published by the Free Software\n * Foundation, either version 3 of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful, but WITHOUT ANY\n * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public License along with\n * this program. If not, see <http\://www.gnu.org/licenses/>.\n */\n${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}\n\n\n\n// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();// ${todo} Auto-generated method stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=false
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/AndroidManifest.xml b/vtm-android/AndroidManifest.xml
similarity index 100%
rename from AndroidManifest.xml
rename to vtm-android/AndroidManifest.xml
diff --git a/COPYING b/vtm-android/COPYING
similarity index 100%
rename from COPYING
rename to vtm-android/COPYING
diff --git a/COPYING.LESSER b/vtm-android/COPYING.LESSER
similarity index 100%
rename from COPYING.LESSER
rename to vtm-android/COPYING.LESSER
diff --git a/README b/vtm-android/README
similarity index 100%
rename from README
rename to vtm-android/README
diff --git a/ant.properties b/vtm-android/ant.properties
similarity index 100%
rename from ant.properties
rename to vtm-android/ant.properties
diff --git a/build.xml b/vtm-android/build.xml
similarity index 100%
rename from build.xml
rename to vtm-android/build.xml
diff --git a/jni/Android.mk b/vtm-android/jni/Android.mk
similarity index 100%
rename from jni/Android.mk
rename to vtm-android/jni/Android.mk
diff --git a/jni/Application.mk b/vtm-android/jni/Application.mk
similarity index 100%
rename from jni/Application.mk
rename to vtm-android/jni/Application.mk
diff --git a/jni/VectorTileMap.cpp b/vtm-android/jni/VectorTileMap.cpp
similarity index 100%
rename from jni/VectorTileMap.cpp
rename to vtm-android/jni/VectorTileMap.cpp
diff --git a/jni/gl/utils.c b/vtm-android/jni/gl/utils.c
similarity index 100%
rename from jni/gl/utils.c
rename to vtm-android/jni/gl/utils.c
diff --git a/jni/tessellate/LICENSE b/vtm-android/jni/tessellate/LICENSE
similarity index 100%
rename from jni/tessellate/LICENSE
rename to vtm-android/jni/tessellate/LICENSE
diff --git a/jni/tessellate/Makefile b/vtm-android/jni/tessellate/Makefile
similarity index 100%
rename from jni/tessellate/Makefile
rename to vtm-android/jni/tessellate/Makefile
diff --git a/jni/tessellate/README.md b/vtm-android/jni/tessellate/README.md
similarity index 100%
rename from jni/tessellate/README.md
rename to vtm-android/jni/tessellate/README.md
diff --git a/jni/tessellate/dict-list.h b/vtm-android/jni/tessellate/dict-list.h
similarity index 100%
rename from jni/tessellate/dict-list.h
rename to vtm-android/jni/tessellate/dict-list.h
diff --git a/jni/tessellate/dict.c b/vtm-android/jni/tessellate/dict.c
similarity index 100%
rename from jni/tessellate/dict.c
rename to vtm-android/jni/tessellate/dict.c
diff --git a/jni/tessellate/dict.h b/vtm-android/jni/tessellate/dict.h
similarity index 100%
rename from jni/tessellate/dict.h
rename to vtm-android/jni/tessellate/dict.h
diff --git a/jni/tessellate/geom.c b/vtm-android/jni/tessellate/geom.c
similarity index 100%
rename from jni/tessellate/geom.c
rename to vtm-android/jni/tessellate/geom.c
diff --git a/jni/tessellate/geom.h b/vtm-android/jni/tessellate/geom.h
similarity index 100%
rename from jni/tessellate/geom.h
rename to vtm-android/jni/tessellate/geom.h
diff --git a/jni/tessellate/glu.h b/vtm-android/jni/tessellate/glu.h
similarity index 100%
rename from jni/tessellate/glu.h
rename to vtm-android/jni/tessellate/glu.h
diff --git a/jni/tessellate/gluos.h b/vtm-android/jni/tessellate/gluos.h
similarity index 100%
rename from jni/tessellate/gluos.h
rename to vtm-android/jni/tessellate/gluos.h
diff --git a/jni/tessellate/main.c b/vtm-android/jni/tessellate/main.c
similarity index 100%
rename from jni/tessellate/main.c
rename to vtm-android/jni/tessellate/main.c
diff --git a/jni/tessellate/memalloc.c b/vtm-android/jni/tessellate/memalloc.c
similarity index 100%
rename from jni/tessellate/memalloc.c
rename to vtm-android/jni/tessellate/memalloc.c
diff --git a/jni/tessellate/memalloc.h b/vtm-android/jni/tessellate/memalloc.h
similarity index 100%
rename from jni/tessellate/memalloc.h
rename to vtm-android/jni/tessellate/memalloc.h
diff --git a/jni/tessellate/mesh.c b/vtm-android/jni/tessellate/mesh.c
similarity index 100%
rename from jni/tessellate/mesh.c
rename to vtm-android/jni/tessellate/mesh.c
diff --git a/jni/tessellate/mesh.h b/vtm-android/jni/tessellate/mesh.h
similarity index 100%
rename from jni/tessellate/mesh.h
rename to vtm-android/jni/tessellate/mesh.h
diff --git a/jni/tessellate/normal.c b/vtm-android/jni/tessellate/normal.c
similarity index 100%
rename from jni/tessellate/normal.c
rename to vtm-android/jni/tessellate/normal.c
diff --git a/jni/tessellate/normal.h b/vtm-android/jni/tessellate/normal.h
similarity index 100%
rename from jni/tessellate/normal.h
rename to vtm-android/jni/tessellate/normal.h
diff --git a/jni/tessellate/priorityq-heap.c b/vtm-android/jni/tessellate/priorityq-heap.c
similarity index 100%
rename from jni/tessellate/priorityq-heap.c
rename to vtm-android/jni/tessellate/priorityq-heap.c
diff --git a/jni/tessellate/priorityq-heap.h b/vtm-android/jni/tessellate/priorityq-heap.h
similarity index 100%
rename from jni/tessellate/priorityq-heap.h
rename to vtm-android/jni/tessellate/priorityq-heap.h
diff --git a/jni/tessellate/priorityq-sort.h b/vtm-android/jni/tessellate/priorityq-sort.h
similarity index 100%
rename from jni/tessellate/priorityq-sort.h
rename to vtm-android/jni/tessellate/priorityq-sort.h
diff --git a/jni/tessellate/priorityq.c b/vtm-android/jni/tessellate/priorityq.c
similarity index 100%
rename from jni/tessellate/priorityq.c
rename to vtm-android/jni/tessellate/priorityq.c
diff --git a/jni/tessellate/priorityq.h b/vtm-android/jni/tessellate/priorityq.h
similarity index 100%
rename from jni/tessellate/priorityq.h
rename to vtm-android/jni/tessellate/priorityq.h
diff --git a/jni/tessellate/render.c b/vtm-android/jni/tessellate/render.c
similarity index 100%
rename from jni/tessellate/render.c
rename to vtm-android/jni/tessellate/render.c
diff --git a/jni/tessellate/render.h b/vtm-android/jni/tessellate/render.h
similarity index 100%
rename from jni/tessellate/render.h
rename to vtm-android/jni/tessellate/render.h
diff --git a/jni/tessellate/sweep.c b/vtm-android/jni/tessellate/sweep.c
similarity index 100%
rename from jni/tessellate/sweep.c
rename to vtm-android/jni/tessellate/sweep.c
diff --git a/jni/tessellate/sweep.h b/vtm-android/jni/tessellate/sweep.h
similarity index 100%
rename from jni/tessellate/sweep.h
rename to vtm-android/jni/tessellate/sweep.h
diff --git a/jni/tessellate/tess.c b/vtm-android/jni/tessellate/tess.c
similarity index 100%
rename from jni/tessellate/tess.c
rename to vtm-android/jni/tessellate/tess.c
diff --git a/jni/tessellate/tess.h b/vtm-android/jni/tessellate/tess.h
similarity index 100%
rename from jni/tessellate/tess.h
rename to vtm-android/jni/tessellate/tess.h
diff --git a/jni/tessellate/tessellate.c b/vtm-android/jni/tessellate/tessellate.c
similarity index 100%
rename from jni/tessellate/tessellate.c
rename to vtm-android/jni/tessellate/tessellate.c
diff --git a/jni/tessellate/tessellate.h b/vtm-android/jni/tessellate/tessellate.h
similarity index 100%
rename from jni/tessellate/tessellate.h
rename to vtm-android/jni/tessellate/tessellate.h
diff --git a/jni/tessellate/tessmono.c b/vtm-android/jni/tessellate/tessmono.c
similarity index 100%
rename from jni/tessellate/tessmono.c
rename to vtm-android/jni/tessellate/tessmono.c
diff --git a/jni/tessellate/tessmono.h b/vtm-android/jni/tessellate/tessmono.h
similarity index 100%
rename from jni/tessellate/tessmono.h
rename to vtm-android/jni/tessellate/tessmono.h
diff --git a/jni/triangle/README b/vtm-android/jni/triangle/README
similarity index 100%
rename from jni/triangle/README
rename to vtm-android/jni/triangle/README
diff --git a/jni/triangle/TriangleJni.c b/vtm-android/jni/triangle/TriangleJni.c
similarity index 100%
rename from jni/triangle/TriangleJni.c
rename to vtm-android/jni/triangle/TriangleJni.c
diff --git a/jni/triangle/triangle.c b/vtm-android/jni/triangle/triangle.c
similarity index 100%
rename from jni/triangle/triangle.c
rename to vtm-android/jni/triangle/triangle.c
diff --git a/jni/triangle/triangle.h b/vtm-android/jni/triangle/triangle.h
similarity index 100%
rename from jni/triangle/triangle.h
rename to vtm-android/jni/triangle/triangle.h
diff --git a/jni/triangle/triangle_dbg.c b/vtm-android/jni/triangle/triangle_dbg.c
similarity index 100%
rename from jni/triangle/triangle_dbg.c
rename to vtm-android/jni/triangle/triangle_dbg.c
diff --git a/jni/triangle/triangle_private.h b/vtm-android/jni/triangle/triangle_private.h
similarity index 100%
rename from jni/triangle/triangle_private.h
rename to vtm-android/jni/triangle/triangle_private.h
diff --git a/vtm-android/lint.xml b/vtm-android/lint.xml
new file mode 100644
index 00000000..8a7b1fac
--- /dev/null
+++ b/vtm-android/lint.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/vtm-android/local.properties b/vtm-android/local.properties
new file mode 100644
index 00000000..116edcd2
--- /dev/null
+++ b/vtm-android/local.properties
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/home/jeff/src/android
diff --git a/myproguard.cfg b/vtm-android/proguard.cfg
similarity index 58%
rename from myproguard.cfg
rename to vtm-android/proguard.cfg
index 91a2a7de..a10bf7ac 100644
--- a/myproguard.cfg
+++ b/vtm-android/proguard.cfg
@@ -1,55 +1,44 @@
--injars bin/classes
-
--libraryjars /home/jeff/src/android/platforms/android-16/android.jar
--libraryjars lib/postgresql-9.0-801.jdbc4.jar
-
--optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-optimizationpasses 5
-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
+-libraryjars lib/postgresql-9.0-801.jdbc4.jar
+-ignorewarnings
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-
-keep public class * extends android.app.Application
-
-keep public class * extends android.app.Service
-
-keep public class * extends android.content.BroadcastReceiver
-
-keep public class * extends android.content.ContentProvider
-
-keep public class * extends android.app.backup.BackupAgentHelper
-
-keep public class * extends android.preference.Preference
-
-keep public class com.android.vending.licensing.ILicensingService
--keepclasseswithmembers class * {
- public (android.content.Context,android.util.AttributeSet);
+-keepclasseswithmembernames class * {
+ native ;
}
-keepclasseswithmembers class * {
- public (android.content.Context,android.util.AttributeSet,int);
+ public (android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public (android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
- public void *(android.view.View);
+ public void *(android.view.View);
}
--keep class * extends android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
-}
-
-# Also keep - Enumerations. Keep the special static methods that are required in
-# enumeration classes.
--keepclassmembers enum * {
+-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-# Keep names - Native method names. Keep all native class/method names.
--keepclasseswithmembers,allowshrinking class * {
- native ;
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
}
diff --git a/vtm-android/project.properties b/vtm-android/project.properties
new file mode 100644
index 00000000..bef2caff
--- /dev/null
+++ b/vtm-android/project.properties
@@ -0,0 +1,16 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+# Project target.
+target=android-17
+
+#proguard.config=proguard.cfg
+android.library=true
diff --git a/res/drawable-nodpi/marker_default.png b/vtm-android/res/drawable-nodpi/marker_default.png
similarity index 100%
rename from res/drawable-nodpi/marker_default.png
rename to vtm-android/res/drawable-nodpi/marker_default.png
diff --git a/res/drawable-nodpi/marker_default_focused_base.png b/vtm-android/res/drawable-nodpi/marker_default_focused_base.png
similarity index 100%
rename from res/drawable-nodpi/marker_default_focused_base.png
rename to vtm-android/res/drawable-nodpi/marker_default_focused_base.png
diff --git a/res/drawable-nodpi/pin.png b/vtm-android/res/drawable-nodpi/pin.png
similarity index 100%
rename from res/drawable-nodpi/pin.png
rename to vtm-android/res/drawable-nodpi/pin.png
diff --git a/src/com/badlogic/gdx/backends/android/AndroidGL20.java b/vtm-android/src/com/badlogic/gdx/backends/android/AndroidGL20.java
similarity index 100%
rename from src/com/badlogic/gdx/backends/android/AndroidGL20.java
rename to vtm-android/src/com/badlogic/gdx/backends/android/AndroidGL20.java
diff --git a/vtm-android/src/org/oscim/android/AndroidAssetAdapter.java b/vtm-android/src/org/oscim/android/AndroidAssetAdapter.java
new file mode 100644
index 00000000..5b88fcc7
--- /dev/null
+++ b/vtm-android/src/org/oscim/android/AndroidAssetAdapter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2013
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.oscim.backend.AssetAdapter;
+
+import android.content.Context;
+
+public class AndroidAssetAdapter extends AssetAdapter {
+ Context mContext;
+ public AndroidAssetAdapter(Context ctx) {
+ mContext = ctx;
+ }
+ @Override
+ public InputStream openFileAsStream(String fileName) {
+ try {
+ return mContext.getAssets().open(fileName);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/src/org/oscim/android/AndroidGLRenderer.java b/vtm-android/src/org/oscim/android/AndroidGLRenderer.java
similarity index 100%
rename from src/org/oscim/android/AndroidGLRenderer.java
rename to vtm-android/src/org/oscim/android/AndroidGLRenderer.java
diff --git a/src/org/oscim/android/AndroidGraphics.java b/vtm-android/src/org/oscim/android/AndroidGraphics.java
similarity index 100%
rename from src/org/oscim/android/AndroidGraphics.java
rename to vtm-android/src/org/oscim/android/AndroidGraphics.java
diff --git a/src/org/oscim/android/AndroidLog.java b/vtm-android/src/org/oscim/android/AndroidLog.java
similarity index 100%
rename from src/org/oscim/android/AndroidLog.java
rename to vtm-android/src/org/oscim/android/AndroidLog.java
diff --git a/src/org/oscim/android/AndroidMapView.java b/vtm-android/src/org/oscim/android/AndroidMapView.java
similarity index 93%
rename from src/org/oscim/android/AndroidMapView.java
rename to vtm-android/src/org/oscim/android/AndroidMapView.java
index 0c67d5ac..bc5f9b49 100644
--- a/src/org/oscim/android/AndroidMapView.java
+++ b/vtm-android/src/org/oscim/android/AndroidMapView.java
@@ -17,7 +17,9 @@ package org.oscim.android;
import org.oscim.android.canvas.AndroidGraphics;
import org.oscim.android.input.AndroidMotionEvent;
+import org.oscim.backend.AssetAdapter;
import org.oscim.backend.CanvasAdapter;
+import org.oscim.backend.GLAdapter;
import org.oscim.backend.Log;
import org.oscim.core.Tile;
import org.oscim.view.MapRenderCallback;
@@ -28,6 +30,8 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.RelativeLayout;
+import com.badlogic.gdx.backends.android.AndroidGL20;
+
/**
* A MapView shows a map on the display of the device. It handles all user input
* and touch gestures to move and zoom the map.
@@ -54,7 +58,12 @@ public class AndroidMapView extends RelativeLayout implements MapRenderCallback
private final MapView mMapView;
static {
+ System.loadLibrary("glutils");
+ System.loadLibrary("triangle");
+ //System.loadLibrary("tessellate");
+
CanvasAdapter.g = AndroidGraphics.INSTANCE;
+ GLAdapter.INSTANCE = new AndroidGL20();
Log.logger = new AndroidLog();
}
@@ -86,7 +95,9 @@ public class AndroidMapView extends RelativeLayout implements MapRenderCallback
throw new IllegalArgumentException(
"context is not an instance of MapActivity");
}
- //CanvasAdapter.g = AndroidCanvas;
+
+ AssetAdapter.g = new AndroidAssetAdapter(context);
+
this.setWillNotDraw(true);
@@ -156,9 +167,9 @@ public class AndroidMapView extends RelativeLayout implements MapRenderCallback
return mMapView.getLayerManager().handleMotionEvent(mMotionEvent);
}
-
+ // synchronized ???
@Override
- protected synchronized void onSizeChanged(int width, int height,
+ protected void onSizeChanged(int width, int height,
int oldWidth, int oldHeight) {
Log.d(TAG, "onSizeChanged: " + width + "x" + height);
diff --git a/src/org/oscim/android/Compass.java b/vtm-android/src/org/oscim/android/Compass.java
similarity index 100%
rename from src/org/oscim/android/Compass.java
rename to vtm-android/src/org/oscim/android/Compass.java
diff --git a/src/org/oscim/android/GLView.java b/vtm-android/src/org/oscim/android/GLView.java
similarity index 100%
rename from src/org/oscim/android/GLView.java
rename to vtm-android/src/org/oscim/android/GLView.java
diff --git a/src/org/oscim/android/GlConfigChooser.java b/vtm-android/src/org/oscim/android/GlConfigChooser.java
similarity index 100%
rename from src/org/oscim/android/GlConfigChooser.java
rename to vtm-android/src/org/oscim/android/GlConfigChooser.java
diff --git a/src/org/oscim/android/MapActivity.java b/vtm-android/src/org/oscim/android/MapActivity.java
similarity index 100%
rename from src/org/oscim/android/MapActivity.java
rename to vtm-android/src/org/oscim/android/MapActivity.java
diff --git a/src/org/oscim/android/MapZoomControls.java b/vtm-android/src/org/oscim/android/MapZoomControls.java
similarity index 100%
rename from src/org/oscim/android/MapZoomControls.java
rename to vtm-android/src/org/oscim/android/MapZoomControls.java
diff --git a/src/org/oscim/android/canvas/AndroidBitmap.java b/vtm-android/src/org/oscim/android/canvas/AndroidBitmap.java
similarity index 100%
rename from src/org/oscim/android/canvas/AndroidBitmap.java
rename to vtm-android/src/org/oscim/android/canvas/AndroidBitmap.java
diff --git a/src/org/oscim/android/canvas/AndroidCanvas.java b/vtm-android/src/org/oscim/android/canvas/AndroidCanvas.java
similarity index 100%
rename from src/org/oscim/android/canvas/AndroidCanvas.java
rename to vtm-android/src/org/oscim/android/canvas/AndroidCanvas.java
diff --git a/src/org/oscim/android/canvas/AndroidGraphics.java b/vtm-android/src/org/oscim/android/canvas/AndroidGraphics.java
similarity index 100%
rename from src/org/oscim/android/canvas/AndroidGraphics.java
rename to vtm-android/src/org/oscim/android/canvas/AndroidGraphics.java
diff --git a/src/org/oscim/android/canvas/AndroidPaint.java b/vtm-android/src/org/oscim/android/canvas/AndroidPaint.java
similarity index 100%
rename from src/org/oscim/android/canvas/AndroidPaint.java
rename to vtm-android/src/org/oscim/android/canvas/AndroidPaint.java
diff --git a/src/org/oscim/android/gl/AndroidGL.java b/vtm-android/src/org/oscim/android/gl/AndroidGL.java
similarity index 100%
rename from src/org/oscim/android/gl/AndroidGL.java
rename to vtm-android/src/org/oscim/android/gl/AndroidGL.java
diff --git a/src/org/oscim/android/input/AndroidMotionEvent.java b/vtm-android/src/org/oscim/android/input/AndroidMotionEvent.java
similarity index 100%
rename from src/org/oscim/android/input/AndroidMotionEvent.java
rename to vtm-android/src/org/oscim/android/input/AndroidMotionEvent.java
diff --git a/vtm-extras/.classpath b/vtm-extras/.classpath
new file mode 100644
index 00000000..1a530a4d
--- /dev/null
+++ b/vtm-extras/.classpath
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm-extras/.project b/vtm-extras/.project
new file mode 100644
index 00000000..60853f9b
--- /dev/null
+++ b/vtm-extras/.project
@@ -0,0 +1,17 @@
+
+
+ vtm-extras
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/vtm-extras/.settings/org.eclipse.jdt.core.prefs b/vtm-extras/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..8000cd6c
--- /dev/null
+++ b/vtm-extras/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/src/org/oscim/utils/Triangulator.java b/vtm-extras/src/org/oscim/utils/Triangulator.java
similarity index 100%
rename from src/org/oscim/utils/Triangulator.java
rename to vtm-extras/src/org/oscim/utils/Triangulator.java
diff --git a/src/org/oscim/utils/osm/Bound.java b/vtm-extras/src/org/oscim/utils/osm/Bound.java
similarity index 100%
rename from src/org/oscim/utils/osm/Bound.java
rename to vtm-extras/src/org/oscim/utils/osm/Bound.java
diff --git a/src/org/oscim/utils/osm/OSMData.java b/vtm-extras/src/org/oscim/utils/osm/OSMData.java
similarity index 100%
rename from src/org/oscim/utils/osm/OSMData.java
rename to vtm-extras/src/org/oscim/utils/osm/OSMData.java
diff --git a/src/org/oscim/utils/osm/OSMElement.java b/vtm-extras/src/org/oscim/utils/osm/OSMElement.java
similarity index 100%
rename from src/org/oscim/utils/osm/OSMElement.java
rename to vtm-extras/src/org/oscim/utils/osm/OSMElement.java
diff --git a/src/org/oscim/utils/osm/OSMMember.java b/vtm-extras/src/org/oscim/utils/osm/OSMMember.java
similarity index 100%
rename from src/org/oscim/utils/osm/OSMMember.java
rename to vtm-extras/src/org/oscim/utils/osm/OSMMember.java
diff --git a/src/org/oscim/utils/osm/OSMNode.java b/vtm-extras/src/org/oscim/utils/osm/OSMNode.java
similarity index 100%
rename from src/org/oscim/utils/osm/OSMNode.java
rename to vtm-extras/src/org/oscim/utils/osm/OSMNode.java
diff --git a/src/org/oscim/utils/osm/OSMRelation.java b/vtm-extras/src/org/oscim/utils/osm/OSMRelation.java
similarity index 100%
rename from src/org/oscim/utils/osm/OSMRelation.java
rename to vtm-extras/src/org/oscim/utils/osm/OSMRelation.java
diff --git a/src/org/oscim/utils/osm/OSMWay.java b/vtm-extras/src/org/oscim/utils/osm/OSMWay.java
similarity index 100%
rename from src/org/oscim/utils/osm/OSMWay.java
rename to vtm-extras/src/org/oscim/utils/osm/OSMWay.java
diff --git a/src/org/oscim/utils/osmpbf/OsmPbfParser.java b/vtm-extras/src/org/oscim/utils/osmpbf/OsmPbfParser.java
similarity index 100%
rename from src/org/oscim/utils/osmpbf/OsmPbfParser.java
rename to vtm-extras/src/org/oscim/utils/osmpbf/OsmPbfParser.java
diff --git a/src/org/oscim/utils/osmpbf/OsmPbfReader.java b/vtm-extras/src/org/oscim/utils/osmpbf/OsmPbfReader.java
similarity index 100%
rename from src/org/oscim/utils/osmpbf/OsmPbfReader.java
rename to vtm-extras/src/org/oscim/utils/osmpbf/OsmPbfReader.java
diff --git a/src/org/oscim/utils/overpass/OverpassAPIReader.java b/vtm-extras/src/org/oscim/utils/overpass/OverpassAPIReader.java
similarity index 100%
rename from src/org/oscim/utils/overpass/OverpassAPIReader.java
rename to vtm-extras/src/org/oscim/utils/overpass/OverpassAPIReader.java
diff --git a/src/org/oscim/utils/wkb/Geometry.java b/vtm-extras/src/org/oscim/utils/wkb/Geometry.java
similarity index 100%
rename from src/org/oscim/utils/wkb/Geometry.java
rename to vtm-extras/src/org/oscim/utils/wkb/Geometry.java
diff --git a/src/org/oscim/utils/wkb/ValueGetter.java b/vtm-extras/src/org/oscim/utils/wkb/ValueGetter.java
similarity index 100%
rename from src/org/oscim/utils/wkb/ValueGetter.java
rename to vtm-extras/src/org/oscim/utils/wkb/ValueGetter.java
diff --git a/src/org/oscim/utils/wkb/WKBReader.java b/vtm-extras/src/org/oscim/utils/wkb/WKBReader.java
similarity index 100%
rename from src/org/oscim/utils/wkb/WKBReader.java
rename to vtm-extras/src/org/oscim/utils/wkb/WKBReader.java
diff --git a/vtm-gdx-android/.classpath b/vtm-gdx-android/.classpath
new file mode 100644
index 00000000..346a9895
--- /dev/null
+++ b/vtm-gdx-android/.classpath
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm-gdx-android/.project b/vtm-gdx-android/.project
new file mode 100644
index 00000000..73270fe9
--- /dev/null
+++ b/vtm-gdx-android/.project
@@ -0,0 +1,40 @@
+
+
+ vtm-gdx-android
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
+
+ assets
+ 2
+ /home/src/vtm/OpenScienceMap/vtm/assets
+
+
+
diff --git a/vtm-gdx-android/.settings/org.eclipse.jdt.core.prefs b/vtm-gdx-android/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..48ab4c6b
--- /dev/null
+++ b/vtm-gdx-android/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/vtm-gdx-android/AndroidManifest.xml b/vtm-gdx-android/AndroidManifest.xml
new file mode 100644
index 00000000..e0a0fdf5
--- /dev/null
+++ b/vtm-gdx-android/AndroidManifest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vtm-gdx-android/proguard.cfg b/vtm-gdx-android/proguard.cfg
new file mode 100644
index 00000000..b1cdf17b
--- /dev/null
+++ b/vtm-gdx-android/proguard.cfg
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+-keepclasseswithmembers class * {
+ public (android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public (android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/vtm-gdx-android/project.properties b/vtm-gdx-android/project.properties
new file mode 100644
index 00000000..c4f09d2b
--- /dev/null
+++ b/vtm-gdx-android/project.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-17
diff --git a/vtm-gdx-android/res/drawable-hdpi/ic_launcher.png b/vtm-gdx-android/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000..8074c4c5
Binary files /dev/null and b/vtm-gdx-android/res/drawable-hdpi/ic_launcher.png differ
diff --git a/vtm-gdx-android/res/drawable-ldpi/ic_launcher.png b/vtm-gdx-android/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 00000000..1095584e
Binary files /dev/null and b/vtm-gdx-android/res/drawable-ldpi/ic_launcher.png differ
diff --git a/vtm-gdx-android/res/drawable-mdpi/ic_launcher.png b/vtm-gdx-android/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..a07c69fa
Binary files /dev/null and b/vtm-gdx-android/res/drawable-mdpi/ic_launcher.png differ
diff --git a/vtm-gdx-android/res/layout/main.xml b/vtm-gdx-android/res/layout/main.xml
new file mode 100644
index 00000000..5c4fde29
--- /dev/null
+++ b/vtm-gdx-android/res/layout/main.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/vtm-gdx-android/res/values/strings.xml b/vtm-gdx-android/res/values/strings.xml
new file mode 100644
index 00000000..227659a0
--- /dev/null
+++ b/vtm-gdx-android/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ My LibGDX Game
+
\ No newline at end of file
diff --git a/src/org/oscim/backend/InputAdapter.java b/vtm-gdx-android/src/org/oscim/android/AndroidLog.java
similarity index 60%
rename from src/org/oscim/backend/InputAdapter.java
rename to vtm-gdx-android/src/org/oscim/android/AndroidLog.java
index 4f9679d5..1c785507 100644
--- a/src/org/oscim/backend/InputAdapter.java
+++ b/vtm-gdx-android/src/org/oscim/android/AndroidLog.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013
+ * Copyright 2013
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -12,8 +12,31 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
-package org.oscim.backend;
+package org.oscim.android;
-public class InputAdapter {
+import android.util.Log;
+
+
+public class AndroidLog implements org.oscim.backend.Log.Logger{
+
+ @Override
+ public void d(String tag, String msg) {
+ Log.d(tag, msg);
+ }
+
+ @Override
+ public void w(String tag, String msg) {
+ Log.w(tag, msg);
+ }
+
+ @Override
+ public void e(String tag, String msg) {
+ Log.e(tag, msg);
+ }
+
+ @Override
+ public void i(String tag, String msg) {
+ Log.i(tag, msg);
+ }
}
diff --git a/vtm-gdx-android/src/org/oscim/android/canvas/AndroidBitmap.java b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidBitmap.java
new file mode 100644
index 00000000..ffd6f174
--- /dev/null
+++ b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidBitmap.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2013 Hannes Janetzek
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.canvas;
+
+import java.io.InputStream;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+
+public class AndroidBitmap implements org.oscim.backend.canvas.Bitmap {
+ final Bitmap mBitmap;
+
+ public AndroidBitmap(InputStream inputStream) {
+ mBitmap = BitmapFactory.decodeStream(inputStream);
+ }
+
+ /**
+ * @param format ignored always ARGB8888
+ */
+ public AndroidBitmap(int width, int height, int format){
+ mBitmap = android.graphics.Bitmap
+ .createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888);
+ }
+ AndroidBitmap(android.graphics.Bitmap bitmap){
+ mBitmap = bitmap;
+ }
+
+ @Override
+ public int getWidth() {
+ return mBitmap.getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return mBitmap.getHeight();
+ }
+
+ @Override
+ public int[] getPixels() {
+ int width = getWidth();
+ int height = getHeight();
+ int[] colors = new int[width * height];
+ mBitmap.getPixels(colors, 0, width, 0, 0, width, height);
+ return colors;
+ }
+
+ @Override
+ public void eraseColor(int color) {
+ //int a = android.graphics.Color.TRANSPARENT;
+ mBitmap.eraseColor(color);
+ }
+
+ @Override
+ public int uploadToTexture(boolean replace) {
+
+ int format = GLUtils.getInternalFormat(mBitmap);
+ int type = GLUtils.getType(mBitmap);
+
+ if (replace)
+ GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap, format,
+ type);
+ else
+ GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, format, mBitmap, type, 0);
+
+ return 0;
+ }
+
+ @Override
+ public void recycle() {
+ mBitmap.recycle();
+ }
+}
diff --git a/vtm-gdx-android/src/org/oscim/android/canvas/AndroidCanvas.java b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidCanvas.java
new file mode 100644
index 00000000..ac93ceac
--- /dev/null
+++ b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidCanvas.java
@@ -0,0 +1,29 @@
+package org.oscim.android.canvas;
+
+import org.oscim.backend.canvas.Bitmap;
+import org.oscim.backend.canvas.Canvas;
+import org.oscim.backend.canvas.Paint;
+
+public class AndroidCanvas implements Canvas {
+ final android.graphics.Canvas canvas;
+
+ public AndroidCanvas() {
+ this.canvas = new android.graphics.Canvas();
+ }
+ @Override
+ public void setBitmap(Bitmap bitmap) {
+ this.canvas.setBitmap(((AndroidBitmap)bitmap).mBitmap);
+ }
+
+ @Override
+ public void drawText(String string, float x, float y, Paint stroke) {
+ this.canvas.drawText(string, x, y, ((AndroidPaint)stroke).mPaint);
+
+ }
+ @Override
+ public void drawBitmap(Bitmap bitmap, float x, float y) {
+ this.canvas.drawBitmap(((AndroidBitmap)bitmap).mBitmap, x, y, null);
+
+ }
+
+}
diff --git a/vtm-gdx-android/src/org/oscim/android/canvas/AndroidGraphics.java b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidGraphics.java
new file mode 100644
index 00000000..e2ac5260
--- /dev/null
+++ b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidGraphics.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2010, 2011, 2012 mapsforge.org
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.canvas;
+
+import java.io.InputStream;
+
+import org.oscim.backend.CanvasAdapter;
+import org.oscim.backend.canvas.Bitmap;
+import org.oscim.backend.canvas.Canvas;
+import org.oscim.backend.canvas.Paint;
+import org.oscim.layers.overlay.OverlayItem.HotspotPlace;
+import org.oscim.layers.overlay.OverlayMarker;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap.Config;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+
+public final class AndroidGraphics extends CanvasAdapter {
+ public static final AndroidGraphics INSTANCE = new AndroidGraphics();
+
+ // public static android.graphics.Bitmap getAndroidBitmap(Bitmap bitmap) {
+ // return ((AndroidBitmap) bitmap).bitmap;
+ // }
+
+ public static android.graphics.Paint getAndroidPaint(Paint paint) {
+ return ((AndroidPaint) paint).mPaint;
+ }
+
+ private AndroidGraphics() {
+ // do nothing
+ }
+
+ @Override
+ public Bitmap decodeBitmap(InputStream inputStream) {
+ return new AndroidBitmap(inputStream);
+ }
+
+ @Override
+ public int getColor(Color color) {
+ switch (color) {
+ case BLACK:
+ return android.graphics.Color.BLACK;
+
+ case CYAN:
+ return android.graphics.Color.CYAN;
+
+ case TRANSPARENT:
+ return android.graphics.Color.TRANSPARENT;
+
+ case WHITE:
+ return android.graphics.Color.WHITE;
+ }
+
+ throw new IllegalArgumentException("unknown color value: " + color);
+ }
+
+ @Override
+ public Paint getPaint() {
+ return new AndroidPaint();
+ }
+
+ @Override
+ public int parseColor(String colorString) {
+ return android.graphics.Color.parseColor(colorString);
+ }
+
+ @Override
+ public Bitmap getBitmap(int width, int height, int format) {
+ return new AndroidBitmap(width, height, format);
+ }
+
+ @Override
+ public Canvas getCanvas() {
+ return new AndroidCanvas();
+ }
+
+ //-------------------------------------
+ public static Bitmap drawableToBitmap(Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ return new AndroidBitmap(((BitmapDrawable) drawable).getBitmap());
+ }
+
+ android.graphics.Bitmap bitmap = android.graphics.Bitmap.createBitmap(
+ drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(),
+ Config.ARGB_8888);
+
+ android.graphics.Canvas canvas = new android.graphics.Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+
+ return new AndroidBitmap(bitmap);
+ }
+
+ public static OverlayMarker makeMarker(Resources res, int id, HotspotPlace place) {
+
+ if (place == null)
+ place = HotspotPlace.CENTER;
+
+ Drawable drawable = res.getDrawable(id);
+
+ return new OverlayMarker(drawableToBitmap(drawable), place);
+ }
+}
diff --git a/vtm-gdx-android/src/org/oscim/android/canvas/AndroidPaint.java b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidPaint.java
new file mode 100644
index 00000000..0c112dba
--- /dev/null
+++ b/vtm-gdx-android/src/org/oscim/android/canvas/AndroidPaint.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2010, 2011, 2012 mapsforge.org
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.android.canvas;
+
+import org.oscim.backend.canvas.Paint;
+
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapShader;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint.FontMetrics;
+import android.graphics.PathEffect;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.Shader.TileMode;
+import android.graphics.Typeface;
+
+class AndroidPaint implements Paint {
+ private static int getStyle(org.oscim.backend.canvas.Paint.FontStyle fontStyle) {
+ switch (fontStyle) {
+ case BOLD:
+ return 1;
+ case BOLD_ITALIC:
+ return 3;
+ case ITALIC:
+ return 2;
+ case NORMAL:
+ return 0;
+ }
+
+ throw new IllegalArgumentException("unknown font style: " + fontStyle);
+ }
+
+ private static Typeface getTypeface(org.oscim.backend.canvas.Paint.FontFamily fontFamily) {
+ switch (fontFamily) {
+ case DEFAULT:
+ return Typeface.DEFAULT;
+ case DEFAULT_BOLD:
+ return Typeface.DEFAULT_BOLD;
+ case MONOSPACE:
+ return Typeface.MONOSPACE;
+ case SANS_SERIF:
+ return Typeface.SANS_SERIF;
+ case SERIF:
+ return Typeface.SERIF;
+ }
+
+ throw new IllegalArgumentException("unknown font family: " + fontFamily);
+ }
+
+ final android.graphics.Paint mPaint;
+
+ AndroidPaint() {
+ mPaint = new android.graphics.Paint(
+ android.graphics.Paint.ANTI_ALIAS_FLAG);
+ }
+
+ @Override
+ public int getColor() {
+ return mPaint.getColor();
+ }
+
+ @Override
+ public int getTextHeight(String text) {
+ Rect rect = new Rect();
+ mPaint.getTextBounds(text, 0, text.length(), rect);
+ return rect.height();
+ }
+
+ @Override
+ public int getTextWidth(String text) {
+ Rect rect = new Rect();
+ mPaint.getTextBounds(text, 0, text.length(), rect);
+ return rect.width();
+ }
+
+ @Override
+ public void setBitmapShader(org.oscim.backend.canvas.Bitmap bitmap) {
+ if (bitmap == null) {
+ return;
+ }
+
+ android.graphics.Bitmap androidBitmap = android.graphics.Bitmap
+ .createBitmap(bitmap.getPixels(), bitmap.getWidth(),
+ bitmap.getHeight(), Config.ARGB_8888);
+ Shader shader = new BitmapShader(androidBitmap, TileMode.REPEAT,
+ TileMode.REPEAT);
+ mPaint.setShader(shader);
+ }
+
+ @Override
+ public void setColor(int color) {
+ mPaint.setColor(color);
+ }
+
+ @Override
+ public void setDashPathEffect(float[] strokeDasharray) {
+ PathEffect pathEffect = new DashPathEffect(strokeDasharray, 0);
+ mPaint.setPathEffect(pathEffect);
+ }
+
+ @Override
+ public void setStrokeCap(Cap cap) {
+ android.graphics.Paint.Cap androidCap = android.graphics.Paint.Cap
+ .valueOf(cap.name());
+ mPaint.setStrokeCap(androidCap);
+ }
+
+ @Override
+ public void setStrokeWidth(float width) {
+ mPaint.setStrokeWidth(width);
+ }
+
+ @Override
+ public void setStyle(Style style) {
+ mPaint.setStyle(android.graphics.Paint.Style.valueOf(style.name()));
+ }
+
+ @Override
+ public void setTextAlign(Align align) {
+
+ mPaint.setTextAlign(android.graphics.Paint.Align.valueOf(align.name()));
+ }
+
+ @Override
+ public void setTextSize(float textSize) {
+ mPaint.setTextSize(textSize);
+ }
+
+ @Override
+ public void setTypeface(FontFamily fontFamily, FontStyle fontStyle) {
+ Typeface typeface = Typeface.create(getTypeface(fontFamily),
+ getStyle(fontStyle));
+ mPaint.setTypeface(typeface);
+ }
+
+ @Override
+ public float measureText(String text) {
+ return mPaint.measureText(text);
+ }
+
+ @Override
+ public float getFontHeight() {
+ FontMetrics fm = mPaint.getFontMetrics();
+ return (float) Math.ceil(Math.abs(fm.bottom) + Math.abs(fm.top));
+ }
+
+ @Override
+ public float getFontDescent() {
+ FontMetrics fm = mPaint.getFontMetrics();
+ // //fontDescent = (float) Math.ceil(Math.abs(fm.descent));
+ return Math.abs(fm.bottom);
+ }
+}
diff --git a/vtm-gdx-android/src/org/oscim/gdx/MainActivity.java b/vtm-gdx-android/src/org/oscim/gdx/MainActivity.java
new file mode 100644
index 00000000..729eaa3d
--- /dev/null
+++ b/vtm-gdx-android/src/org/oscim/gdx/MainActivity.java
@@ -0,0 +1,39 @@
+package org.oscim.gdx;
+
+import org.oscim.android.AndroidLog;
+import org.oscim.android.canvas.AndroidGraphics;
+import org.oscim.backend.AssetAdapter;
+import org.oscim.backend.CanvasAdapter;
+import org.oscim.backend.GL20;
+import org.oscim.backend.GLAdapter;
+import org.oscim.backend.Log;
+import org.oscim.core.Tile;
+
+import android.os.Bundle;
+
+import com.badlogic.gdx.backends.android.AndroidApplication;
+import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
+import com.badlogic.gdx.backends.android.AndroidGL20;
+
+public class MainActivity extends AndroidApplication {
+
+ private final class AndroidGLAdapter extends AndroidGL20 implements GL20{
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // set our globals
+ CanvasAdapter.g = AndroidGraphics.INSTANCE;
+ GLAdapter.INSTANCE = new AndroidGLAdapter();
+ Log.logger = new AndroidLog();
+ // TODO make this dpi dependent
+ Tile.SIZE = 400;
+
+ AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
+ cfg.useGL20 = true;
+
+ initialize(new GdxMap(), cfg);
+ }
+}
\ No newline at end of file
diff --git a/vtm-gdx-desktop/.classpath b/vtm-gdx-desktop/.classpath
new file mode 100644
index 00000000..b24402d4
--- /dev/null
+++ b/vtm-gdx-desktop/.classpath
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm-gdx-desktop/.project b/vtm-gdx-desktop/.project
new file mode 100644
index 00000000..7bf43a15
--- /dev/null
+++ b/vtm-gdx-desktop/.project
@@ -0,0 +1,24 @@
+
+
+ vtm-gdx-desktop
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
+
+ assets
+ 2
+ /home/src/vtm/OpenScienceMap/vtm/assets
+
+
+
diff --git a/vtm-gdx-desktop/.settings/org.eclipse.jdt.core.prefs b/vtm-gdx-desktop/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..54e493c0
--- /dev/null
+++ b/vtm-gdx-desktop/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/vtm-gdx-desktop/src/org/oscim/awt/AwtBitmap.java b/vtm-gdx-desktop/src/org/oscim/awt/AwtBitmap.java
new file mode 100644
index 00000000..9895cec9
--- /dev/null
+++ b/vtm-gdx-desktop/src/org/oscim/awt/AwtBitmap.java
@@ -0,0 +1,85 @@
+package org.oscim.awt;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.IntBuffer;
+
+import javax.imageio.ImageIO;
+
+import org.oscim.backend.canvas.Bitmap;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.GL20;
+import com.badlogic.gdx.utils.BufferUtils;
+
+public class AwtBitmap implements Bitmap {
+
+ BufferedImage bitmap;
+ int width;
+ int height;
+
+ public AwtBitmap(int width, int height, int format) {
+ bitmap = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ this.width = width;
+ this.height = height;
+ }
+
+ AwtBitmap(InputStream inputStream) throws IOException {
+ this.bitmap = ImageIO.read(inputStream);
+}
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+
+ @Override
+ public int[] getPixels() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void eraseColor(int transparent) {
+ // TODO Auto-generated method stub
+ }
+
+ private static IntBuffer tmpBuffer = BufferUtils.newIntBuffer(256 * 256);
+ private static int[] tmpPixel = new int[256 * 256];
+ @Override
+ public int uploadToTexture(boolean replace) {
+ int[] pixels;
+ IntBuffer buffer;
+
+ if (width == 256 && height == 256){
+ pixels = tmpPixel;
+ buffer = tmpBuffer;
+ buffer.clear();
+ }else{
+ pixels = new int[width * height];
+ buffer = BufferUtils.newIntBuffer(width * height);
+ }
+
+
+ bitmap.getRGB(0, 0, width, height, pixels, 0, width);
+
+ buffer.put(pixels);
+ buffer.flip();
+
+ Gdx.gl20.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, width,
+ height, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, buffer);
+
+ return 0;
+ }
+
+ @Override
+ public void recycle() {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/vtm-gdx-desktop/src/org/oscim/awt/AwtCanvas.java b/vtm-gdx-desktop/src/org/oscim/awt/AwtCanvas.java
new file mode 100644
index 00000000..2452dff1
--- /dev/null
+++ b/vtm-gdx-desktop/src/org/oscim/awt/AwtCanvas.java
@@ -0,0 +1,63 @@
+package org.oscim.awt;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+
+import org.oscim.backend.canvas.Bitmap;
+import org.oscim.backend.canvas.Canvas;
+import org.oscim.backend.canvas.Paint;
+
+public class AwtCanvas implements Canvas {
+
+ Graphics2D canvas;
+
+ public AwtCanvas() {
+
+ }
+
+ @Override
+ public void setBitmap(Bitmap bitmap) {
+ if (canvas != null)
+ canvas.dispose();
+
+ AwtBitmap awtBitamp = (AwtBitmap)bitmap;
+
+ canvas = awtBitamp.bitmap.createGraphics();
+ //awtBitamp.bitmap.
+ //bitmap.eraseColor();
+ canvas.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0));
+ //canvas.setBackground(new Color(1,1,1,1));
+ canvas.setColor(Color.BLACK);
+
+ //Gdx.app.log("set bitmap ", bitmap + " "+ bitmap.getWidth() + " " +bitmap.getHeight());
+ canvas.fillRect(0,0,bitmap.getWidth(),bitmap.getHeight());
+ //canvas.clearRect(0, 0, bitmap.getWidth(),bitmap.getHeight());
+
+ canvas.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+
+ canvas.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
+ //canvas.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ //canvas.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ //canvas.setRenderingHint(RenderingHints.KEY_KERNING, RenderingHints.VALUE_RENDER_QUALITY);
+
+
+ }
+
+ @Override
+ public void drawText(String string, float x, float y, Paint stroke) {
+ AwtPaint p = (AwtPaint)stroke;
+
+ canvas.setFont(p.font);
+ canvas.setColor(p.color);
+
+ canvas.drawString(string, (int)x, (int)y);
+ }
+
+ @Override
+ public void drawBitmap(Bitmap bitmap, float x, float y) {
+ // TODO Auto-generated method stub
+ throw new UnknownError("not implemented");
+ }
+}
diff --git a/vtm-gdx-desktop/src/org/oscim/awt/AwtGraphics.java b/vtm-gdx-desktop/src/org/oscim/awt/AwtGraphics.java
new file mode 100644
index 00000000..944b2b28
--- /dev/null
+++ b/vtm-gdx-desktop/src/org/oscim/awt/AwtGraphics.java
@@ -0,0 +1,89 @@
+package org.oscim.awt;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.oscim.backend.canvas.Bitmap;
+import org.oscim.backend.canvas.Canvas;
+import org.oscim.backend.CanvasAdapter;
+import org.oscim.backend.canvas.Paint;
+
+public class AwtGraphics extends CanvasAdapter {
+ public static final AwtGraphics INSTANCE = new AwtGraphics();
+
+ private AwtGraphics() {
+ // do nothing
+ }
+
+ @Override
+ public int getColor(Color color) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public Paint getPaint() {
+ return new AwtPaint();
+ }
+
+ @Override
+ public int parseColor(String colorString) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public Bitmap getBitmap(int width, int height, int format) {
+ return new AwtBitmap(width, height, format);
+ }
+
+ @Override
+ public Canvas getCanvas() {
+ return new AwtCanvas();
+ }
+
+ static final BufferedImage image;
+
+ static final Graphics2D canvas;
+
+ static {
+ image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
+ canvas = image.createGraphics();
+ canvas.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
+ //canvas.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ //canvas.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ }
+ static synchronized FontMetrics getFontMetrics(Font font) {
+ canvas.setFont(font);
+ // get character measurements
+ FontMetrics fm = canvas.getFontMetrics();
+ // int ascent = fm.getMaxAscent();
+ // int descent = fm.getMaxDescent();
+ // int advance = fm.charWidth('W'); // width of widest char, more
+ // reliable than getMaxAdvance();
+ // int leading = fm.getLeading();
+ //
+ return fm;
+ }
+
+ static synchronized float getTextWidth(FontMetrics fm, String text) {
+ return (float)fm.getStringBounds(text, canvas).getWidth();
+ }
+
+ @Override
+ public Bitmap decodeBitmap(InputStream inputStream) {
+ try {
+ return new AwtBitmap(inputStream);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+}
diff --git a/vtm-gdx-desktop/src/org/oscim/awt/AwtPaint.java b/vtm-gdx-desktop/src/org/oscim/awt/AwtPaint.java
new file mode 100644
index 00000000..8186240e
--- /dev/null
+++ b/vtm-gdx-desktop/src/org/oscim/awt/AwtPaint.java
@@ -0,0 +1,149 @@
+package org.oscim.awt;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.font.TextAttribute;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.HashMap;
+import java.util.Map;
+
+//import org.oscim.graphics.Align;
+import org.oscim.backend.canvas.Bitmap;
+//import org.oscim.graphics.Cap;
+//import org.oscim.graphics.FontFamily;
+//import org.oscim.graphics.FontStyle;
+import org.oscim.backend.canvas.Paint;
+//import org.oscim.graphics.Style;
+
+public class AwtPaint implements Paint {
+ static final Font defaultFont;
+ static {
+ Map textAttributes = new HashMap();
+ textAttributes.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
+ textAttributes.put(TextAttribute.FAMILY, "SansSerif");
+ textAttributes.put(TextAttribute.SIZE, 13);
+
+ defaultFont = Font.getFont(textAttributes);
+
+ }
+
+ Font font = defaultFont; //new Font("Default", Font.PLAIN, 13);
+
+ FontMetrics fm;
+ Color color = new Color(0.1f,0.1f,0.1f,1);
+
+ @Override
+ public int getColor() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getTextHeight(String text) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getTextWidth(String text) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public void setBitmapShader(Bitmap bitmap) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setColor(int color) {
+ this.color = new Color(
+ ((color >> 16) & 0xff)/255f,
+ ((color >> 8) & 0xff)/255f,
+ ((color >> 0) & 0xff)/255f,
+ ((color >> 24) & 0xff)/255f
+ );
+ }
+
+ @Override
+ public void setDashPathEffect(float[] strokeDasharray) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setStrokeCap(Cap cap) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setStrokeWidth(float width) {
+ //int size = font.getSize();
+ //font = font.deriveFont(size + width * 4);
+
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setStyle(Style style) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTextAlign(Align align) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setTextSize(float textSize) {
+ font = font.deriveFont(textSize - 4);
+
+ }
+
+ @Override
+ public void setTypeface(FontFamily fontFamily, FontStyle fontStyle) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public float measureText(String text) {
+ if (fm == null)
+ fm = AwtGraphics.getFontMetrics(this.font);
+ float w = AwtGraphics.getTextWidth(fm, text);
+ //Gdx.app.log("text width:", text + " " + w);
+ return w;
+ //return fm.getStringBounds(text, A).getWidth();
+ //return AwtGraphics.getTextWidth(fm, text);
+ //return fm.stringWidth(text);
+ }
+
+ @Override
+ public float getFontHeight() {
+ if (fm == null)
+ fm = AwtGraphics.getFontMetrics(this.font);
+
+ float height = fm.getHeight();
+
+ //Gdx.app.log("text height", " " + height);
+ return height;
+ }
+
+ @Override
+ public float getFontDescent() {
+ if (fm == null)
+ fm = AwtGraphics.getFontMetrics(this.font);
+
+ float desc = fm.getDescent();
+ //Gdx.app.log("text descent", " " + desc);
+
+ return desc;
+ }
+
+}
diff --git a/vtm-gdx-desktop/src/org/oscim/gdx/GdxGLAdapter.java b/vtm-gdx-desktop/src/org/oscim/gdx/GdxGLAdapter.java
new file mode 100644
index 00000000..64d7a6d0
--- /dev/null
+++ b/vtm-gdx-desktop/src/org/oscim/gdx/GdxGLAdapter.java
@@ -0,0 +1,742 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+package org.oscim.gdx;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.opengl.EXTFramebufferObject;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL13;
+import org.lwjgl.opengl.GL14;
+import org.lwjgl.opengl.GL15;
+import org.lwjgl.opengl.GL20;
+
+import com.badlogic.gdx.graphics.GL10;
+import com.badlogic.gdx.utils.GdxRuntimeException;
+
+/** An implementation of the {@link GL20} interface based on LWJGL. Note that LWJGL shaders and OpenGL ES shaders will not be 100%
+ * compatible. Some glGetXXX methods are not implemented.
+ *
+ * @author mzechner */
+final class GdxGLAdapter implements org.oscim.backend.GL20 {
+ public void glActiveTexture (int texture) {
+ GL13.glActiveTexture(texture);
+ }
+
+ public void glAttachShader (int program, int shader) {
+ GL20.glAttachShader(program, shader);
+ }
+
+ public void glBindAttribLocation (int program, int index, String name) {
+ GL20.glBindAttribLocation(program, index, name);
+ }
+
+ public void glBindBuffer (int target, int buffer) {
+ GL15.glBindBuffer(target, buffer);
+ }
+
+ public void glBindFramebuffer (int target, int framebuffer) {
+ EXTFramebufferObject.glBindFramebufferEXT(target, framebuffer);
+ }
+
+ public void glBindRenderbuffer (int target, int renderbuffer) {
+ EXTFramebufferObject.glBindRenderbufferEXT(target, renderbuffer);
+ }
+
+ public void glBindTexture (int target, int texture) {
+ GL11.glBindTexture(target, texture);
+ }
+
+ public void glBlendColor (float red, float green, float blue, float alpha) {
+ GL14.glBlendColor(red, green, blue, alpha);
+ }
+
+ public void glBlendEquation (int mode) {
+ GL14.glBlendEquation(mode);
+ }
+
+ public void glBlendEquationSeparate (int modeRGB, int modeAlpha) {
+ GL20.glBlendEquationSeparate(modeRGB, modeAlpha);
+ }
+
+ public void glBlendFunc (int sfactor, int dfactor) {
+ GL11.glBlendFunc(sfactor, dfactor);
+ }
+
+ public void glBlendFuncSeparate (int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
+ GL14.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ }
+
+ public void glBufferData (int target, int size, Buffer data, int usage) {
+ if(data == null)
+ throw new GdxRuntimeException("Using null for the data not possible, blame LWJGL");
+ else if (data instanceof ByteBuffer)
+ GL15.glBufferData(target, (ByteBuffer)data, usage);
+ else if (data instanceof IntBuffer)
+ GL15.glBufferData(target, (IntBuffer)data, usage);
+ else if (data instanceof FloatBuffer)
+ GL15.glBufferData(target, (FloatBuffer)data, usage);
+ else if (data instanceof DoubleBuffer)
+ GL15.glBufferData(target, (DoubleBuffer)data, usage);
+ else if (data instanceof ShortBuffer) //
+ GL15.glBufferData(target, (ShortBuffer)data, usage);
+ }
+
+ public void glBufferSubData (int target, int offset, int size, Buffer data) {
+ if(data == null)
+ throw new GdxRuntimeException("Using null for the data not possible, blame LWJGL");
+ else if (data instanceof ByteBuffer)
+ GL15.glBufferSubData(target, offset, (ByteBuffer)data);
+ else if (data instanceof IntBuffer)
+ GL15.glBufferSubData(target, offset, (IntBuffer)data);
+ else if (data instanceof FloatBuffer)
+ GL15.glBufferSubData(target, offset, (FloatBuffer)data);
+ else if (data instanceof DoubleBuffer)
+ GL15.glBufferSubData(target, offset, (DoubleBuffer)data);
+ else if (data instanceof ShortBuffer) //
+ GL15.glBufferSubData(target, offset, (ShortBuffer)data);
+ }
+
+ public int glCheckFramebufferStatus (int target) {
+ return EXTFramebufferObject.glCheckFramebufferStatusEXT(target);
+ }
+
+ public void glClear (int mask) {
+ GL11.glClear(mask);
+ }
+
+ public void glClearColor (float red, float green, float blue, float alpha) {
+ GL11.glClearColor(red, green, blue, alpha);
+ }
+
+ public void glClearDepthf (float depth) {
+ GL11.glClearDepth(depth);
+ }
+
+ public void glClearStencil (int s) {
+ GL11.glClearStencil(s);
+ }
+
+ public void glColorMask (boolean red, boolean green, boolean blue, boolean alpha) {
+ GL11.glColorMask(red, green, blue, alpha);
+ }
+
+ public void glCompileShader (int shader) {
+ GL20.glCompileShader(shader);
+ }
+
+ public void glCompressedTexImage2D (int target, int level, int internalformat, int width, int height, int border,
+ int imageSize, Buffer data) {
+ if (data instanceof ByteBuffer) {
+ GL13.glCompressedTexImage2D(target, level, internalformat, width, height, border, (ByteBuffer)data);
+ } else {
+ throw new GdxRuntimeException("Can't use " + data.getClass().getName()
+ + " with this method. Use ByteBuffer instead.");
+ }
+ }
+
+ public void glCompressedTexSubImage2D (int target, int level, int xoffset, int yoffset, int width, int height, int format,
+ int imageSize, Buffer data) {
+ throw new GdxRuntimeException("not implemented");
+ }
+
+ public void glCopyTexImage2D (int target, int level, int internalformat, int x, int y, int width, int height, int border) {
+ GL11.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ }
+
+ public void glCopyTexSubImage2D (int target, int level, int xoffset, int yoffset, int x, int y, int width, int height) {
+ GL11.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+ }
+
+ public int glCreateProgram () {
+ return GL20.glCreateProgram();
+ }
+
+ public int glCreateShader (int type) {
+ return GL20.glCreateShader(type);
+ }
+
+ public void glCullFace (int mode) {
+ GL11.glCullFace(mode);
+ }
+
+ public void glDeleteBuffers (int n, IntBuffer buffers) {
+ GL15.glDeleteBuffers(buffers);
+ }
+
+ public void glDeleteFramebuffers (int n, IntBuffer framebuffers) {
+ EXTFramebufferObject.glDeleteFramebuffersEXT(framebuffers);
+ }
+
+ public void glDeleteProgram (int program) {
+ GL20.glDeleteProgram(program);
+ }
+
+ public void glDeleteRenderbuffers (int n, IntBuffer renderbuffers) {
+ EXTFramebufferObject.glDeleteRenderbuffersEXT(renderbuffers);
+ }
+
+ public void glDeleteShader (int shader) {
+ GL20.glDeleteShader(shader);
+ }
+
+ public void glDeleteTextures (int n, IntBuffer textures) {
+ GL11.glDeleteTextures(textures);
+ }
+
+ public void glDepthFunc (int func) {
+ GL11.glDepthFunc(func);
+ }
+
+ public void glDepthMask (boolean flag) {
+ GL11.glDepthMask(flag);
+ }
+
+ public void glDepthRangef (float zNear, float zFar) {
+ GL11.glDepthRange(zNear, zFar);
+ }
+
+ public void glDetachShader (int program, int shader) {
+ GL20.glDetachShader(program, shader);
+ }
+
+ public void glDisable (int cap) {
+ GL11.glDisable(cap);
+ }
+
+ public void glDisableVertexAttribArray (int index) {
+ GL20.glDisableVertexAttribArray(index);
+ }
+
+ public void glDrawArrays (int mode, int first, int count) {
+ GL11.glDrawArrays(mode, first, count);
+ }
+
+ public void glDrawElements (int mode, int count, int type, Buffer indices) {
+ if (indices instanceof ShortBuffer && type == GL10.GL_UNSIGNED_SHORT)
+ GL11.glDrawElements(mode, (ShortBuffer)indices);
+ else if (indices instanceof ByteBuffer && type == GL10.GL_UNSIGNED_SHORT)
+ GL11.glDrawElements(mode, ((ByteBuffer)indices).asShortBuffer()); // FIXME yay...
+ else if (indices instanceof ByteBuffer && type == GL10.GL_UNSIGNED_BYTE)
+ GL11.glDrawElements(mode, (ByteBuffer)indices);
+ else
+ throw new GdxRuntimeException("Can't use " + indices.getClass().getName()
+ + " with this method. Use ShortBuffer or ByteBuffer instead. Blame LWJGL");
+ }
+
+ public void glEnable (int cap) {
+ GL11.glEnable(cap);
+ }
+
+ public void glEnableVertexAttribArray (int index) {
+ GL20.glEnableVertexAttribArray(index);
+ }
+
+ public void glFinish () {
+ GL11.glFinish();
+ }
+
+ public void glFlush () {
+ GL11.glFlush();
+ }
+
+ public void glFramebufferRenderbuffer (int target, int attachment, int renderbuffertarget, int renderbuffer) {
+ EXTFramebufferObject.glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer);
+ }
+
+ public void glFramebufferTexture2D (int target, int attachment, int textarget, int texture, int level) {
+ EXTFramebufferObject.glFramebufferTexture2DEXT(target, attachment, textarget, texture, level);
+ }
+
+ public void glFrontFace (int mode) {
+ GL11.glFrontFace(mode);
+ }
+
+ public void glGenBuffers (int n, IntBuffer buffers) {
+ GL15.glGenBuffers(buffers);
+ }
+
+ public void glGenFramebuffers (int n, IntBuffer framebuffers) {
+ EXTFramebufferObject.glGenFramebuffersEXT(framebuffers);
+ }
+
+ public void glGenRenderbuffers (int n, IntBuffer renderbuffers) {
+ EXTFramebufferObject.glGenRenderbuffersEXT(renderbuffers);
+ }
+
+ public void glGenTextures (int n, IntBuffer textures) {
+ GL11.glGenTextures(textures);
+ }
+
+ public void glGenerateMipmap (int target) {
+ EXTFramebufferObject.glGenerateMipmapEXT(target);
+ }
+
+ public String glGetActiveAttrib (int program, int index, IntBuffer size, Buffer type) {
+ // FIXME this is less than ideal of course...
+ IntBuffer typeTmp = BufferUtils.createIntBuffer(2);
+ String name = GL20.glGetActiveAttrib(program, index, 256, typeTmp);
+ if (type instanceof IntBuffer) ((IntBuffer)type).put(typeTmp.get(0));
+ return name;
+ }
+
+ public String glGetActiveUniform (int program, int index, IntBuffer size, Buffer type) {
+ // FIXME this is less than ideal of course...
+ IntBuffer typeTmp = BufferUtils.createIntBuffer(2);
+ String name = GL20.glGetActiveUniform(program, index, 256, typeTmp);
+ if (type instanceof IntBuffer) ((IntBuffer)type).put(typeTmp.get(0));
+ return name;
+ }
+
+ public void glGetAttachedShaders (int program, int maxcount, Buffer count, IntBuffer shaders) {
+ GL20.glGetAttachedShaders(program, (IntBuffer)count, shaders);
+ }
+
+ public int glGetAttribLocation (int program, String name) {
+ return GL20.glGetAttribLocation(program, name);
+ }
+
+ public void glGetBooleanv (int pname, Buffer params) {
+ GL11.glGetBoolean(pname, (ByteBuffer)params);
+ }
+
+ public void glGetBufferParameteriv (int target, int pname, IntBuffer params) {
+ GL15.glGetBufferParameter(target, pname, params);
+ }
+
+ public int glGetError () {
+ return GL11.glGetError();
+ }
+
+ public void glGetFloatv (int pname, FloatBuffer params) {
+ GL11.glGetFloat(pname, params);
+ }
+
+ public void glGetFramebufferAttachmentParameteriv (int target, int attachment, int pname, IntBuffer params) {
+ EXTFramebufferObject.glGetFramebufferAttachmentParameterEXT(target, attachment, pname, params);
+ }
+
+ public void glGetIntegerv (int pname, IntBuffer params) {
+ GL11.glGetInteger(pname, params);
+ }
+
+ public String glGetProgramInfoLog (int program) {
+ ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 10);
+ buffer.order(ByteOrder.nativeOrder());
+ ByteBuffer tmp = ByteBuffer.allocateDirect(4);
+ tmp.order(ByteOrder.nativeOrder());
+ IntBuffer intBuffer = tmp.asIntBuffer();
+
+ GL20.glGetProgramInfoLog(program, intBuffer, buffer);
+ int numBytes = intBuffer.get(0);
+ byte[] bytes = new byte[numBytes];
+ buffer.get(bytes);
+ return new String(bytes);
+ }
+
+ public void glGetProgramiv (int program, int pname, IntBuffer params) {
+ GL20.glGetProgram(program, pname, params);
+ }
+
+ public void glGetRenderbufferParameteriv (int target, int pname, IntBuffer params) {
+ EXTFramebufferObject.glGetRenderbufferParameterEXT(target, pname, params);
+ }
+
+ public String glGetShaderInfoLog (int shader) {
+ ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 10);
+ buffer.order(ByteOrder.nativeOrder());
+ ByteBuffer tmp = ByteBuffer.allocateDirect(4);
+ tmp.order(ByteOrder.nativeOrder());
+ IntBuffer intBuffer = tmp.asIntBuffer();
+
+ GL20.glGetShaderInfoLog(shader, intBuffer, buffer);
+ int numBytes = intBuffer.get(0);
+ byte[] bytes = new byte[numBytes];
+ buffer.get(bytes);
+ return new String(bytes);
+ }
+
+ public void glGetShaderPrecisionFormat (int shadertype, int precisiontype, IntBuffer range, IntBuffer precision) {
+ throw new UnsupportedOperationException("unsupported, won't implement");
+ }
+
+ public void glGetShaderSource (int shader, int bufsize, Buffer length, String source) {
+ throw new UnsupportedOperationException("unsupported, won't implement.");
+ }
+
+ public void glGetShaderiv (int shader, int pname, IntBuffer params) {
+ GL20.glGetShader(shader, pname, params);
+ }
+
+ public String glGetString (int name) {
+ return GL11.glGetString(name);
+ }
+
+ public void glGetTexParameterfv (int target, int pname, FloatBuffer params) {
+ GL11.glGetTexParameter(target, pname, params);
+ }
+
+ public void glGetTexParameteriv (int target, int pname, IntBuffer params) {
+ GL11.glGetTexParameter(target, pname, params);
+ }
+
+ public int glGetUniformLocation (int program, String name) {
+ return GL20.glGetUniformLocation(program, name);
+ }
+
+ public void glGetUniformfv (int program, int location, FloatBuffer params) {
+ GL20.glGetUniform(program, location, params);
+ }
+
+ public void glGetUniformiv (int program, int location, IntBuffer params) {
+ GL20.glGetUniform(program, location, params);
+ }
+
+ public void glGetVertexAttribPointerv (int index, int pname, Buffer pointer) {
+ throw new UnsupportedOperationException("unsupported, won't implement");
+ }
+
+ public void glGetVertexAttribfv (int index, int pname, FloatBuffer params) {
+ GL20.glGetVertexAttrib(index, pname, params);
+ }
+
+ public void glGetVertexAttribiv (int index, int pname, IntBuffer params) {
+ GL20.glGetVertexAttrib(index, pname, params);
+ }
+
+ public void glHint (int target, int mode) {
+ GL11.glHint(target, mode);
+ }
+
+ public boolean glIsBuffer (int buffer) {
+ return GL15.glIsBuffer(buffer);
+ }
+
+ public boolean glIsEnabled (int cap) {
+ return GL11.glIsEnabled(cap);
+ }
+
+ public boolean glIsFramebuffer (int framebuffer) {
+ return EXTFramebufferObject.glIsFramebufferEXT(framebuffer);
+ }
+
+ public boolean glIsProgram (int program) {
+ return GL20.glIsProgram(program);
+ }
+
+ public boolean glIsRenderbuffer (int renderbuffer) {
+ return EXTFramebufferObject.glIsRenderbufferEXT(renderbuffer);
+ }
+
+ public boolean glIsShader (int shader) {
+ return GL20.glIsShader(shader);
+ }
+
+ public boolean glIsTexture (int texture) {
+ return GL11.glIsTexture(texture);
+ }
+
+ public void glLineWidth (float width) {
+ GL11.glLineWidth(width);
+ }
+
+ public void glLinkProgram (int program) {
+ GL20.glLinkProgram(program);
+ }
+
+ public void glPixelStorei (int pname, int param) {
+ GL11.glPixelStorei(pname, param);
+ }
+
+ public void glPolygonOffset (float factor, float units) {
+ GL11.glPolygonOffset(factor, units);
+ }
+
+ public void glReadPixels (int x, int y, int width, int height, int format, int type, Buffer pixels) {
+ if (pixels instanceof ByteBuffer)
+ GL11.glReadPixels(x, y, width, height, format, type, (ByteBuffer)pixels);
+ else if (pixels instanceof ShortBuffer)
+ GL11.glReadPixels(x, y, width, height, format, type, (ShortBuffer)pixels);
+ else if (pixels instanceof IntBuffer)
+ GL11.glReadPixels(x, y, width, height, format, type, (IntBuffer)pixels);
+ else if (pixels instanceof FloatBuffer)
+ GL11.glReadPixels(x, y, width, height, format, type, (FloatBuffer)pixels);
+ else
+ throw new GdxRuntimeException("Can't use " + pixels.getClass().getName()
+ + " with this method. Use ByteBuffer, ShortBuffer, IntBuffer or FloatBuffer instead. Blame LWJGL");
+ }
+
+ public void glReleaseShaderCompiler () {
+ // nothing to do here
+ }
+
+ public void glRenderbufferStorage (int target, int internalformat, int width, int height) {
+ EXTFramebufferObject.glRenderbufferStorageEXT(target, internalformat, width, height);
+ }
+
+ public void glSampleCoverage (float value, boolean invert) {
+ GL13.glSampleCoverage(value, invert);
+ }
+
+ public void glScissor (int x, int y, int width, int height) {
+ GL11.glScissor(x, y, width, height);
+ }
+
+ public void glShaderBinary (int n, IntBuffer shaders, int binaryformat, Buffer binary, int length) {
+ throw new UnsupportedOperationException("unsupported, won't implement");
+ }
+
+ public void glShaderSource (int shader, String string) {
+ GL20.glShaderSource(shader, string);
+ }
+
+ public void glStencilFunc (int func, int ref, int mask) {
+ GL11.glStencilFunc(func, ref, mask);
+ }
+
+ public void glStencilFuncSeparate (int face, int func, int ref, int mask) {
+ GL20.glStencilFuncSeparate(face, func, ref, mask);
+ }
+
+ public void glStencilMask (int mask) {
+ GL11.glStencilMask(mask);
+ }
+
+ public void glStencilMaskSeparate (int face, int mask) {
+ GL20.glStencilMaskSeparate(face, mask);
+ }
+
+ public void glStencilOp (int fail, int zfail, int zpass) {
+ GL11.glStencilOp(fail, zfail, zpass);
+ }
+
+ public void glStencilOpSeparate (int face, int fail, int zfail, int zpass) {
+ GL20.glStencilOpSeparate(face, fail, zfail, zpass);
+ }
+
+ public void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type,
+ Buffer pixels) {
+ if (pixels == null)
+ GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, (ByteBuffer)null);
+ else if (pixels instanceof ByteBuffer)
+ GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, (ByteBuffer)pixels);
+ else if (pixels instanceof ShortBuffer)
+ GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, (ShortBuffer)pixels);
+ else if (pixels instanceof IntBuffer)
+ GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, (IntBuffer)pixels);
+ else if (pixels instanceof FloatBuffer)
+ GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, (FloatBuffer)pixels);
+ else if (pixels instanceof DoubleBuffer)
+ GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, (DoubleBuffer)pixels);
+ else
+ throw new GdxRuntimeException("Can't use " + pixels.getClass().getName()
+ + " with this method. Use ByteBuffer, ShortBuffer, IntBuffer, FloatBuffer or DoubleBuffer instead. Blame LWJGL");
+ }
+
+ public void glTexParameterf (int target, int pname, float param) {
+ GL11.glTexParameterf(target, pname, param);
+ }
+
+ public void glTexParameterfv (int target, int pname, FloatBuffer params) {
+ GL11.glTexParameter(target, pname, params);
+ }
+
+ public void glTexParameteri (int target, int pname, int param) {
+ GL11.glTexParameteri(target, pname, param);
+ }
+
+ public void glTexParameteriv (int target, int pname, IntBuffer params) {
+ GL11.glTexParameter(target, pname, params);
+ }
+
+ public void glTexSubImage2D (int target, int level, int xoffset, int yoffset, int width, int height, int format, int type,
+ Buffer pixels) {
+ if (pixels instanceof ByteBuffer)
+ GL11.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, (ByteBuffer)pixels);
+ else if (pixels instanceof ShortBuffer)
+ GL11.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, (ShortBuffer)pixels);
+ else if (pixels instanceof IntBuffer)
+ GL11.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, (IntBuffer)pixels);
+ else if (pixels instanceof FloatBuffer)
+ GL11.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, (FloatBuffer)pixels);
+ else if (pixels instanceof DoubleBuffer)
+ GL11.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, (DoubleBuffer)pixels);
+ else
+ throw new GdxRuntimeException("Can't use " + pixels.getClass().getName()
+ + " with this method. Use ByteBuffer, ShortBuffer, IntBuffer, FloatBuffer or DoubleBuffer instead. Blame LWJGL");
+ }
+
+ public void glUniform1f (int location, float x) {
+ GL20.glUniform1f(location, x);
+ }
+
+ public void glUniform1fv (int location, int count, FloatBuffer v) {
+ GL20.glUniform1(location, v);
+ }
+
+ public void glUniform1i (int location, int x) {
+ GL20.glUniform1i(location, x);
+ }
+
+ public void glUniform1iv (int location, int count, IntBuffer v) {
+ GL20.glUniform1(location, v);
+ }
+
+ public void glUniform2f (int location, float x, float y) {
+ GL20.glUniform2f(location, x, y);
+ }
+
+ public void glUniform2fv (int location, int count, FloatBuffer v) {
+ GL20.glUniform2(location, v);
+ }
+
+ public void glUniform2i (int location, int x, int y) {
+ GL20.glUniform2i(location, x, y);
+ }
+
+ public void glUniform2iv (int location, int count, IntBuffer v) {
+ GL20.glUniform2(location, v);
+ }
+
+ public void glUniform3f (int location, float x, float y, float z) {
+ GL20.glUniform3f(location, x, y, z);
+ }
+
+ public void glUniform3fv (int location, int count, FloatBuffer v) {
+ GL20.glUniform3(location, v);
+ }
+
+ public void glUniform3i (int location, int x, int y, int z) {
+ GL20.glUniform3i(location, x, y, z);
+ }
+
+ public void glUniform3iv (int location, int count, IntBuffer v) {
+ GL20.glUniform3(location, v);
+ }
+
+ public void glUniform4f (int location, float x, float y, float z, float w) {
+ GL20.glUniform4f(location, x, y, z, w);
+ }
+
+ public void glUniform4fv (int location, int count, FloatBuffer v) {
+ GL20.glUniform4(location, v);
+ }
+
+ public void glUniform4i (int location, int x, int y, int z, int w) {
+ GL20.glUniform4i(location, x, y, z, w);
+ }
+
+ public void glUniform4iv (int location, int count, IntBuffer v) {
+ GL20.glUniform4(location, v);
+ }
+
+ public void glUniformMatrix2fv (int location, int count, boolean transpose, FloatBuffer value) {
+ GL20.glUniformMatrix2(location, transpose, value);
+ }
+
+ public void glUniformMatrix3fv (int location, int count, boolean transpose, FloatBuffer value) {
+ GL20.glUniformMatrix3(location, transpose, value);
+ }
+
+ public void glUniformMatrix4fv (int location, int count, boolean transpose, FloatBuffer value) {
+ GL20.glUniformMatrix4(location, transpose, value);
+ }
+
+ public void glUseProgram (int program) {
+ GL20.glUseProgram(program);
+ }
+
+ public void glValidateProgram (int program) {
+ GL20.glValidateProgram(program);
+ }
+
+ public void glVertexAttrib1f (int indx, float x) {
+ GL20.glVertexAttrib1f(indx, x);
+ }
+
+ public void glVertexAttrib1fv (int indx, FloatBuffer values) {
+ GL20.glVertexAttrib1f(indx, values.get());
+ }
+
+ public void glVertexAttrib2f (int indx, float x, float y) {
+ GL20.glVertexAttrib2f(indx, x, y);
+ }
+
+ public void glVertexAttrib2fv (int indx, FloatBuffer values) {
+ GL20.glVertexAttrib2f(indx, values.get(), values.get());
+ }
+
+ public void glVertexAttrib3f (int indx, float x, float y, float z) {
+ GL20.glVertexAttrib3f(indx, x, y, z);
+ }
+
+ public void glVertexAttrib3fv (int indx, FloatBuffer values) {
+ GL20.glVertexAttrib3f(indx, values.get(), values.get(), values.get());
+ }
+
+ public void glVertexAttrib4f (int indx, float x, float y, float z, float w) {
+ GL20.glVertexAttrib4f(indx, x, y, z, w);
+ }
+
+ public void glVertexAttrib4fv (int indx, FloatBuffer values) {
+ GL20.glVertexAttrib4f(indx, values.get(), values.get(), values.get(), values.get());
+ }
+
+ public void glVertexAttribPointer (int indx, int size, int type, boolean normalized, int stride, Buffer buffer) {
+ if (buffer instanceof ByteBuffer) {
+ if (type == GL_BYTE)
+ GL20.glVertexAttribPointer(indx, size, false, normalized, stride, (ByteBuffer)buffer);
+ else if (type == GL_UNSIGNED_BYTE)
+ GL20.glVertexAttribPointer(indx, size, true, normalized, stride, (ByteBuffer)buffer);
+ else if (type == GL_SHORT)
+ GL20.glVertexAttribPointer(indx, size, false, normalized, stride, ((ByteBuffer)buffer).asShortBuffer());
+ else if (type == GL_UNSIGNED_SHORT)
+ GL20.glVertexAttribPointer(indx, size, true, normalized, stride, ((ByteBuffer)buffer).asShortBuffer());
+ else if (type == GL_FLOAT)
+ GL20.glVertexAttribPointer(indx, size, normalized, stride, ((ByteBuffer)buffer).asFloatBuffer());
+ else
+ throw new GdxRuntimeException(
+ "Can't use "
+ + buffer.getClass().getName()
+ + " with type "
+ + type
+ + " with this method. Use ByteBuffer and one of GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT or GL_FLOAT for type. Blame LWJGL");
+ } else
+ throw new GdxRuntimeException("Can't use " + buffer.getClass().getName()
+ + " with this method. Use ByteBuffer instead. Blame LWJGL");
+ }
+
+ public void glViewport (int x, int y, int width, int height) {
+ GL11.glViewport(x, y, width, height);
+ }
+
+ public void glDrawElements (int mode, int count, int type, int indices) {
+ GL11.glDrawElements(mode, count, type, indices);
+ }
+
+ public void glVertexAttribPointer (int indx, int size, int type, boolean normalized, int stride, int ptr) {
+ GL20.glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
+ }
+
+}
diff --git a/vtm-gdx-desktop/src/org/oscim/gdx/Main.java b/vtm-gdx-desktop/src/org/oscim/gdx/Main.java
new file mode 100644
index 00000000..568bf1be
--- /dev/null
+++ b/vtm-gdx-desktop/src/org/oscim/gdx/Main.java
@@ -0,0 +1,29 @@
+package org.oscim.gdx;
+
+import org.oscim.awt.AwtGraphics;
+import org.oscim.backend.CanvasAdapter;
+import org.oscim.backend.GLAdapter;
+import org.oscim.core.Tile;
+
+import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
+import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
+
+public class Main {
+
+ public static void main(String[] args) {
+ LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
+ cfg.title = "vtm-gdx";
+ cfg.useGL20 = true;
+ cfg.width = 1280;
+ cfg.height = 800;
+ cfg.stencil= 8;
+ //cfg.samples = 4;
+
+ // set our globals
+ CanvasAdapter.g = AwtGraphics.INSTANCE;
+ GLAdapter.INSTANCE = new GdxGLAdapter();
+ Tile.SIZE = 256;
+
+ new LwjglApplication(new GdxMap(), cfg);
+ }
+}
diff --git a/vtm-gdx-html/.classpath b/vtm-gdx-html/.classpath
new file mode 100644
index 00000000..f8a695fa
--- /dev/null
+++ b/vtm-gdx-html/.classpath
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm-gdx-html/.project b/vtm-gdx-html/.project
new file mode 100644
index 00000000..56fa9c33
--- /dev/null
+++ b/vtm-gdx-html/.project
@@ -0,0 +1,28 @@
+
+
+ vtm-gdx-html
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.google.gdt.eclipse.core.webAppProjectValidator
+
+
+
+
+ com.google.gwt.eclipse.core.gwtProjectValidator
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ com.google.gwt.eclipse.core.gwtNature
+
+
diff --git a/vtm-gdx-html/.settings/com.google.gdt.eclipse.core.prefs b/vtm-gdx-html/.settings/com.google.gdt.eclipse.core.prefs
new file mode 100644
index 00000000..11a59ec3
--- /dev/null
+++ b/vtm-gdx-html/.settings/com.google.gdt.eclipse.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+jarsExcludedFromWebInfLib=
+warSrcDir=war
+warSrcDirIsOutput=true
diff --git a/vtm-gdx-html/.settings/com.google.gwt.eclipse.core.prefs b/vtm-gdx-html/.settings/com.google.gwt.eclipse.core.prefs
new file mode 100644
index 00000000..150d1cb6
--- /dev/null
+++ b/vtm-gdx-html/.settings/com.google.gwt.eclipse.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+entryPointModules=
+filesCopiedToWebInfLib=gwt-servlet.jar
+gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+UFJFVFRZPC9vdXRwdXQtc3R5bGU+PGV4dHJhLWFyZ3M+PCFbQ0RBVEFbXV0+PC9leHRyYS1hcmdzPjx2bS1hcmdzPjwhW0NEQVRBWy1YbXg1MTJtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+b3JnLm9zY2ltLmdkeC5Hd3REZWZpbml0aW9uPC9lbnRyeS1wb2ludC1tb2R1bGU+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
diff --git a/vtm-gdx-html/src/org/oscim/gdx/GwtDefinition.gwt.xml b/vtm-gdx-html/src/org/oscim/gdx/GwtDefinition.gwt.xml
new file mode 100644
index 00000000..774e9625
--- /dev/null
+++ b/vtm-gdx-html/src/org/oscim/gdx/GwtDefinition.gwt.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vtm-gdx-html/src/org/oscim/gdx/client/GwtLauncher.java b/vtm-gdx-html/src/org/oscim/gdx/client/GwtLauncher.java
new file mode 100644
index 00000000..49f1dcee
--- /dev/null
+++ b/vtm-gdx-html/src/org/oscim/gdx/client/GwtLauncher.java
@@ -0,0 +1,19 @@
+package org.oscim.gdx.client;
+
+import org.oscim.gdx.GdxMap;
+import com.badlogic.gdx.ApplicationListener;
+import com.badlogic.gdx.backends.gwt.GwtApplication;
+import com.badlogic.gdx.backends.gwt.GwtApplicationConfiguration;
+
+public class GwtLauncher extends GwtApplication {
+ @Override
+ public GwtApplicationConfiguration getConfig () {
+ GwtApplicationConfiguration cfg = new GwtApplicationConfiguration(480, 320);
+ return cfg;
+ }
+
+ @Override
+ public ApplicationListener getApplicationListener () {
+ return new GdxMap();
+ }
+}
\ No newline at end of file
diff --git a/vtm-gdx-html/war/WEB-INF/web.xml b/vtm-gdx-html/war/WEB-INF/web.xml
new file mode 100644
index 00000000..a0e8eb7f
--- /dev/null
+++ b/vtm-gdx-html/war/WEB-INF/web.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
diff --git a/vtm-gdx-html/war/index.html b/vtm-gdx-html/war/index.html
new file mode 100644
index 00000000..8dab95a6
--- /dev/null
+++ b/vtm-gdx-html/war/index.html
@@ -0,0 +1,35 @@
+
+
+
+ vtm-gdx
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm-gdx/.classpath b/vtm-gdx/.classpath
new file mode 100644
index 00000000..2e40bfda
--- /dev/null
+++ b/vtm-gdx/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/vtm-gdx/.project b/vtm-gdx/.project
new file mode 100644
index 00000000..0b1ec7e5
--- /dev/null
+++ b/vtm-gdx/.project
@@ -0,0 +1,17 @@
+
+
+ vtm-gdx
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/vtm-gdx/.settings/com.google.gwt.eclipse.core.prefs b/vtm-gdx/.settings/com.google.gwt.eclipse.core.prefs
new file mode 100644
index 00000000..82c36afe
--- /dev/null
+++ b/vtm-gdx/.settings/com.google.gwt.eclipse.core.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+filesCopiedToWebInfLib=
diff --git a/vtm-gdx/.settings/org.eclipse.jdt.core.prefs b/vtm-gdx/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..54e493c0
--- /dev/null
+++ b/vtm-gdx/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/vtm-gdx/src/GdxMap.gwt.xml b/vtm-gdx/src/GdxMap.gwt.xml
new file mode 100644
index 00000000..8adef5ef
--- /dev/null
+++ b/vtm-gdx/src/GdxMap.gwt.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/vtm-gdx/src/org/oscim/gdx/GdxAssetAdapter.java b/vtm-gdx/src/org/oscim/gdx/GdxAssetAdapter.java
new file mode 100644
index 00000000..aac705e2
--- /dev/null
+++ b/vtm-gdx/src/org/oscim/gdx/GdxAssetAdapter.java
@@ -0,0 +1,20 @@
+package org.oscim.gdx;
+
+import java.io.InputStream;
+
+import org.oscim.backend.AssetAdapter;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.files.FileHandle;
+
+public class GdxAssetAdapter extends AssetAdapter{
+
+ @Override
+ public InputStream openFileAsStream(String fileName) {
+ FileHandle file = Gdx.files.internal(fileName);
+ if (file == null)
+ throw new IllegalArgumentException("missing file " + fileName);
+
+ return file.read();
+ }
+}
diff --git a/vtm-gdx/src/org/oscim/gdx/GdxLog.java b/vtm-gdx/src/org/oscim/gdx/GdxLog.java
new file mode 100644
index 00000000..3741d5d7
--- /dev/null
+++ b/vtm-gdx/src/org/oscim/gdx/GdxLog.java
@@ -0,0 +1,30 @@
+package org.oscim.gdx;
+
+import org.oscim.backend.Log.Logger;
+
+import com.badlogic.gdx.Gdx;
+
+public class GdxLog implements Logger {
+
+ @Override
+ public void d(String tag, String msg) {
+ Gdx.app.log(tag, msg);
+
+ }
+
+ @Override
+ public void w(String tag, String msg) {
+ Gdx.app.log(tag, msg);
+ }
+
+ @Override
+ public void e(String tag, String msg) {
+ Gdx.app.log(tag, msg);
+ }
+
+ @Override
+ public void i(String tag, String msg) {
+ Gdx.app.log(tag, msg);
+ }
+
+}
diff --git a/vtm-gdx/src/org/oscim/gdx/GdxMap.java b/vtm-gdx/src/org/oscim/gdx/GdxMap.java
new file mode 100644
index 00000000..ffc358f0
--- /dev/null
+++ b/vtm-gdx/src/org/oscim/gdx/GdxMap.java
@@ -0,0 +1,380 @@
+package org.oscim.gdx;
+
+import org.oscim.backend.AssetAdapter;
+import org.oscim.backend.GL20;
+import org.oscim.backend.Log;
+import org.oscim.backend.input.MotionEvent;
+import org.oscim.layers.tile.vector.MapTileLayer;
+import org.oscim.renderer.GLRenderer;
+import org.oscim.renderer.GLState;
+import org.oscim.theme.InternalRenderTheme;
+import org.oscim.tilesource.TileSource;
+import org.oscim.tilesource.oscimap4.OSciMap4TileSource;
+import org.oscim.view.MapRenderCallback;
+import org.oscim.view.MapView;
+import org.oscim.view.MapViewPosition;
+
+import com.badlogic.gdx.ApplicationListener;
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Input.Buttons;
+import com.badlogic.gdx.InputProcessor;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
+import com.badlogic.gdx.scenes.scene2d.Stage;
+import com.badlogic.gdx.scenes.scene2d.ui.Label;
+import com.badlogic.gdx.utils.SharedLibraryLoader;
+
+public class GdxMap implements ApplicationListener, MapRenderCallback {
+
+ private final MapView mMapView;
+ private final GLRenderer mMapRenderer;
+
+ public GdxMap() {
+ new SharedLibraryLoader().load("vtm-jni");
+
+ AssetAdapter.g = new GdxAssetAdapter();
+
+ mMapView = new MapView(this);
+ mMapRenderer = new GLRenderer(mMapView);
+ }
+
+ Stage ui;
+ Label fps;
+ BitmapFont font;
+
+ @Override
+ public void create() {
+
+ // Gdx.graphics.setContinuousRendering(false);
+
+ if (Log.logger == null)
+ Log.logger = new GdxLog();
+
+ Gdx.app.log("gdx says", "Hi!");
+ Log.d("vtm says", "Hi!");
+
+ int w = Gdx.graphics.getWidth();
+ int h = Gdx.graphics.getHeight();
+ mWidth = w;
+ mHeight = h;
+
+ // TileSource tileSource = new OSciMap2TileSource();
+ // tileSource.setOption("url",
+ // "http://city.informatik.uni-bremen.de/osci/map-live");
+ TileSource tileSource = new OSciMap4TileSource();
+ tileSource.setOption("url", "http://city.informatik.uni-bremen.de/osci/testing");
+
+ MapTileLayer l = mMapView.setBaseMap(tileSource);
+ l.setRenderTheme(InternalRenderTheme.DEFAULT);
+
+ // mMapView.getLayerManager().add(new GenericOverlay(mMapView, new
+ // GridRenderLayer(mMapView)));
+
+ mMapView.getMapViewPosition().setViewport(w, h);
+
+ mMapRenderer.onSurfaceCreated();
+ mMapRenderer.onSurfaceChanged(w, h);
+
+ Gdx.input.setInputProcessor(new TouchHandler());
+
+ ui = new Stage(w, h, false);
+
+ font = new BitmapFont(false);
+
+ fps = new Label("fps: 0", new Label.LabelStyle(font, Color.WHITE));
+ fps.setPosition(10, 30);
+ fps.setColor(0, 1, 0, 1);
+ ui.addActor(fps);
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+ private int fpsCnt = 0;
+ @Override
+ public void render() {
+ // GLState.enableVertexArrays(-1, -1);
+ // GLState.blend(false);
+ // GLState.test(false, false);
+
+ mMapRenderer.onDrawFrame();
+
+ // Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
+
+ // Gdx.gl20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ int f = Gdx.graphics.getFramesPerSecond();
+ if (f != fpsCnt){
+ Log.d("fps", ">" +f);
+ fpsCnt = f;
+ }
+ // fps.setText("fps: " + Gdx.graphics.getFramesPerSecond());
+ // ui.draw();
+ }
+
+ @Override
+ public void resize(int w, int h) {
+ mWidth = w;
+ mHeight = h;
+
+ mMapView.getMapViewPosition().setViewport(w, h);
+ mMapRenderer.onSurfaceChanged(w, h);
+ }
+
+ @Override
+ public void pause() {
+ }
+
+ @Override
+ public void resume() {
+ }
+
+ /**
+ * Update all Layers on Main thread.
+ *
+ * @param forceRedraw
+ * also render frame FIXME (does nothing atm)
+ */
+ void redrawMapInternal(boolean forceRedraw) {
+
+ if (forceRedraw && !mClearMap)
+ Gdx.graphics.requestRendering();
+
+ mMapView.updateLayers();
+
+ if (mClearMap) {
+ Gdx.graphics.requestRendering();
+ mClearMap = false;
+ }
+ }
+
+ private boolean mClearMap;
+
+ public void clearMap() {
+ mClearMap = true;
+ }
+
+ /* private */boolean mWaitRedraw;
+ private final Runnable mRedrawRequest = new Runnable() {
+ @Override
+ public void run() {
+ mWaitRedraw = false;
+ redrawMapInternal(false);
+ }
+ };
+
+ @Override
+ public void updateMap(boolean forceRender) {
+ if (!mWaitRedraw) {
+ mWaitRedraw = true;
+ Gdx.app.postRunnable(mRedrawRequest);
+ }
+ }
+
+ @Override
+ public void renderMap() {
+ if (mClearMap)
+ updateMap(false);
+ else
+ Gdx.graphics.requestRendering();
+ }
+
+ int mHeight, mWidth;
+
+ @Override
+ public int getWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getHeight() {
+ return mHeight;
+ }
+
+ class GdxMotionEvent extends MotionEvent {
+
+ @Override
+ public int getAction() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getX() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getY() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getX(int idx) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public float getY(int idx) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int getPointerCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ }
+
+ class TouchHandler implements InputProcessor {
+
+ private MapViewPosition mMapPosition;
+
+ public TouchHandler() {
+ mMapPosition = mMapView.getMapViewPosition();
+ }
+
+ private boolean mActiveScale;
+ private boolean mActiveTilt;
+ private boolean mActiveRotate;
+
+ private int mPosX, mPosY;
+
+ @Override
+ public boolean keyDown(int keycode) {
+ // switch (keycode) {
+ //
+ // case Input.Keys.UP:
+ // mMapPosition.moveMap(0, -50);
+ // mMapView.redrawMap(true);
+ // break;
+ // case Input.Keys.DOWN:
+ // mMapPosition.moveMap(0, 50);
+ // mMapView.redrawMap(true);
+ // break;
+ // case Input.Keys.LEFT:
+ // mMapPosition.moveMap(-50, 0);
+ // mMapView.redrawMap(true);
+ // break;
+ // case Input.Keys.RIGHT:
+ // mMapPosition.moveMap(50, 0);
+ // mMapView.redrawMap(true);
+ // break;
+ //
+ // case Input.Keys.R:
+ // mMapView.setRenderTheme(InternalRenderTheme.DEFAULT);
+ // mMapView.redrawMap(true);
+ // break;
+ //
+ // case Input.Keys.T:
+ // mMapView.setRenderTheme(InternalRenderTheme.TRONRENDER);
+ // mMapView.redrawMap(true);
+ // break;
+ //
+ // }
+ return true;
+ }
+
+ @Override
+ public boolean keyUp(int keycode) {
+ return false;
+ }
+
+ @Override
+ public boolean keyTyped(char character) {
+ return false;
+ }
+
+ @Override
+ public boolean touchDown(int screenX, int screenY, int pointer,
+ int button) {
+
+ if (button == Buttons.MIDDLE) {
+ mActiveScale = true;
+ // mActiveTilt = true;
+ mPosY = screenY;
+ } else if (button == Buttons.RIGHT) {
+ mActiveRotate = true;
+ mPosX = screenX;
+ mPosY = screenY;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean touchUp(int screenX, int screenY, int pointer, int button) {
+ // Log.d(TAG, "touch up " + pointer);
+ mActiveScale = false;
+ mActiveTilt = false;
+ mActiveRotate = false;
+
+ return false;
+ }
+
+ @Override
+ public boolean touchDragged(int screenX, int screenY, int pointer) {
+ boolean changed = false;
+
+ if (mActiveScale) {
+ // changed = mMapPosition.tilt((screenY - mStartY) / 5f);
+ changed = mMapPosition.scaleMap(1 - (screenY - mPosY) / 100f,
+ 0, 0);
+ mPosY = screenY;
+ return true;
+ }
+
+ if (mActiveRotate) {
+ mMapPosition.rotateMap((screenX - mPosX) / 500f, 0, 0);
+ mPosX = screenX;
+ mMapPosition.tiltMap((screenY - mPosY) / 10f);
+ mPosY = screenY;
+ changed = true;
+ }
+
+ if (!(mActiveRotate || mActiveTilt)) {
+ int dx = screenX - mPosX;
+ int dy = screenY - mPosY;
+ if (Math.abs(dx) > 0 || Math.abs(dy) > 0) {
+ mMapPosition.moveMap(dx, dy);
+ mPosX = screenX;
+ mPosY = screenY;
+ changed = true;
+ }
+ }
+
+ if (changed)
+ updateMap(false);
+
+ return true;
+ }
+
+ @Override
+ public boolean mouseMoved(int screenX, int screenY) {
+ mPosX = screenX;
+ mPosY = screenY;
+ return false;
+ }
+
+ @Override
+ public boolean scrolled(int amount) {
+ float fx = mPosX - mMapView.getWidth() / 2;
+ float fy = mPosY - mMapView.getHeight() / 2;
+
+ if (amount > 0)
+ mMapPosition.scaleMap(0.9f, fx, fy);
+ else
+ mMapPosition.scaleMap(1.1f, fx, fy);
+
+ updateMap(false);
+
+ return true;
+ }
+
+ }
+}
diff --git a/vtm/.classpath b/vtm/.classpath
new file mode 100644
index 00000000..a07fe32a
--- /dev/null
+++ b/vtm/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/vtm/.cproject b/vtm/.cproject
new file mode 100644
index 00000000..0d0f1cf4
--- /dev/null
+++ b/vtm/.cproject
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm/.project b/vtm/.project
new file mode 100644
index 00000000..99a31c7b
--- /dev/null
+++ b/vtm/.project
@@ -0,0 +1,36 @@
+
+
+ vtm
+
+
+
+
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder (1).launch
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/vtm/.settings/org.eclipse.cdt.codan.core.prefs b/vtm/.settings/org.eclipse.cdt.codan.core.prefs
new file mode 100644
index 00000000..9c7ec59a
--- /dev/null
+++ b/vtm/.settings/org.eclipse.cdt.codan.core.prefs
@@ -0,0 +1,66 @@
+eclipse.preferences.version=1
+org.eclipse.cdt.codan.checkers.errnoreturn=Warning
+org.eclipse.cdt.codan.checkers.errnoreturn.params={implicit\=>false}
+org.eclipse.cdt.codan.checkers.errreturnvalue=Error
+org.eclipse.cdt.codan.checkers.errreturnvalue.params={}
+org.eclipse.cdt.codan.checkers.noreturn=Error
+org.eclipse.cdt.codan.checkers.noreturn.params={implicit\=>false}
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false}
+org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
+org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={unknown\=>false,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments=-Error
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={}
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={paramNot\=>false}
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={else\=>false,afterelse\=>false}
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={macro\=>true,exceptions\=>("@(\#)","$Id")}
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=-Error
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+useParentScope=false
diff --git a/src/org/oscim/theme/styles/carto.xml b/vtm/assets/styles/carto.xml
similarity index 100%
rename from src/org/oscim/theme/styles/carto.xml
rename to vtm/assets/styles/carto.xml
diff --git a/src/org/oscim/theme/styles/default.xml b/vtm/assets/styles/default.xml
similarity index 100%
rename from src/org/oscim/theme/styles/default.xml
rename to vtm/assets/styles/default.xml
diff --git a/src/org/oscim/theme/styles/maki.png b/vtm/assets/styles/maki.png
similarity index 100%
rename from src/org/oscim/theme/styles/maki.png
rename to vtm/assets/styles/maki.png
diff --git a/src/org/oscim/theme/styles/osmarender.xml b/vtm/assets/styles/osmarender.xml
similarity index 100%
rename from src/org/oscim/theme/styles/osmarender.xml
rename to vtm/assets/styles/osmarender.xml
diff --git a/src/org/oscim/theme/styles/symbols/airport.png b/vtm/assets/styles/symbols/airport.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/airport.png
rename to vtm/assets/styles/symbols/airport.png
diff --git a/src/org/oscim/theme/styles/symbols/alpine_hut.png b/vtm/assets/styles/symbols/alpine_hut.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/alpine_hut.png
rename to vtm/assets/styles/symbols/alpine_hut.png
diff --git a/src/org/oscim/theme/styles/symbols/atm.png b/vtm/assets/styles/symbols/atm.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/atm.png
rename to vtm/assets/styles/symbols/atm.png
diff --git a/src/org/oscim/theme/styles/symbols/bakery.png b/vtm/assets/styles/symbols/bakery.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/bakery.png
rename to vtm/assets/styles/symbols/bakery.png
diff --git a/src/org/oscim/theme/styles/symbols/bank.png b/vtm/assets/styles/symbols/bank.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/bank.png
rename to vtm/assets/styles/symbols/bank.png
diff --git a/src/org/oscim/theme/styles/symbols/bench.png b/vtm/assets/styles/symbols/bench.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/bench.png
rename to vtm/assets/styles/symbols/bench.png
diff --git a/src/org/oscim/theme/styles/symbols/bicycle_rental.png b/vtm/assets/styles/symbols/bicycle_rental.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/bicycle_rental.png
rename to vtm/assets/styles/symbols/bicycle_rental.png
diff --git a/src/org/oscim/theme/styles/symbols/bus.png b/vtm/assets/styles/symbols/bus.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/bus.png
rename to vtm/assets/styles/symbols/bus.png
diff --git a/src/org/oscim/theme/styles/symbols/bus_sta.png b/vtm/assets/styles/symbols/bus_sta.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/bus_sta.png
rename to vtm/assets/styles/symbols/bus_sta.png
diff --git a/src/org/oscim/theme/styles/symbols/cable_car.png b/vtm/assets/styles/symbols/cable_car.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/cable_car.png
rename to vtm/assets/styles/symbols/cable_car.png
diff --git a/src/org/oscim/theme/styles/symbols/cafe.png b/vtm/assets/styles/symbols/cafe.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/cafe.png
rename to vtm/assets/styles/symbols/cafe.png
diff --git a/src/org/oscim/theme/styles/symbols/campSite.png b/vtm/assets/styles/symbols/campSite.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/campSite.png
rename to vtm/assets/styles/symbols/campSite.png
diff --git a/src/org/oscim/theme/styles/symbols/cave_entrance.png b/vtm/assets/styles/symbols/cave_entrance.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/cave_entrance.png
rename to vtm/assets/styles/symbols/cave_entrance.png
diff --git a/src/org/oscim/theme/styles/symbols/chair_lift_2.png b/vtm/assets/styles/symbols/chair_lift_2.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/chair_lift_2.png
rename to vtm/assets/styles/symbols/chair_lift_2.png
diff --git a/src/org/oscim/theme/styles/symbols/church.png b/vtm/assets/styles/symbols/church.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/church.png
rename to vtm/assets/styles/symbols/church.png
diff --git a/src/org/oscim/theme/styles/symbols/cinema.png b/vtm/assets/styles/symbols/cinema.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/cinema.png
rename to vtm/assets/styles/symbols/cinema.png
diff --git a/src/org/oscim/theme/styles/symbols/drinking_water.png b/vtm/assets/styles/symbols/drinking_water.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/drinking_water.png
rename to vtm/assets/styles/symbols/drinking_water.png
diff --git a/src/org/oscim/theme/styles/symbols/fastfood.png b/vtm/assets/styles/symbols/fastfood.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/fastfood.png
rename to vtm/assets/styles/symbols/fastfood.png
diff --git a/src/org/oscim/theme/styles/symbols/firebrigade.png b/vtm/assets/styles/symbols/firebrigade.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/firebrigade.png
rename to vtm/assets/styles/symbols/firebrigade.png
diff --git a/src/org/oscim/theme/styles/symbols/florist.png b/vtm/assets/styles/symbols/florist.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/florist.png
rename to vtm/assets/styles/symbols/florist.png
diff --git a/src/org/oscim/theme/styles/symbols/fountain.png b/vtm/assets/styles/symbols/fountain.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/fountain.png
rename to vtm/assets/styles/symbols/fountain.png
diff --git a/src/org/oscim/theme/styles/symbols/gondola.png b/vtm/assets/styles/symbols/gondola.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/gondola.png
rename to vtm/assets/styles/symbols/gondola.png
diff --git a/src/org/oscim/theme/styles/symbols/helipad.png b/vtm/assets/styles/symbols/helipad.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/helipad.png
rename to vtm/assets/styles/symbols/helipad.png
diff --git a/src/org/oscim/theme/styles/symbols/hospital.png b/vtm/assets/styles/symbols/hospital.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/hospital.png
rename to vtm/assets/styles/symbols/hospital.png
diff --git a/src/org/oscim/theme/styles/symbols/hostel.png b/vtm/assets/styles/symbols/hostel.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/hostel.png
rename to vtm/assets/styles/symbols/hostel.png
diff --git a/src/org/oscim/theme/styles/symbols/hotel.png b/vtm/assets/styles/symbols/hotel.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/hotel.png
rename to vtm/assets/styles/symbols/hotel.png
diff --git a/src/org/oscim/theme/styles/symbols/information.png b/vtm/assets/styles/symbols/information.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/information.png
rename to vtm/assets/styles/symbols/information.png
diff --git a/src/org/oscim/theme/styles/symbols/kindergarten.png b/vtm/assets/styles/symbols/kindergarten.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/kindergarten.png
rename to vtm/assets/styles/symbols/kindergarten.png
diff --git a/src/org/oscim/theme/styles/symbols/library.png b/vtm/assets/styles/symbols/library.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/library.png
rename to vtm/assets/styles/symbols/library.png
diff --git a/src/org/oscim/theme/styles/symbols/mosque.png b/vtm/assets/styles/symbols/mosque.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/mosque.png
rename to vtm/assets/styles/symbols/mosque.png
diff --git a/src/org/oscim/theme/styles/symbols/oneway.png b/vtm/assets/styles/symbols/oneway.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/oneway.png
rename to vtm/assets/styles/symbols/oneway.png
diff --git a/src/org/oscim/theme/styles/symbols/parking.png b/vtm/assets/styles/symbols/parking.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/parking.png
rename to vtm/assets/styles/symbols/parking.png
diff --git a/src/org/oscim/theme/styles/symbols/peak.png b/vtm/assets/styles/symbols/peak.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/peak.png
rename to vtm/assets/styles/symbols/peak.png
diff --git a/src/org/oscim/theme/styles/symbols/petrolStation.png b/vtm/assets/styles/symbols/petrolStation.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/petrolStation.png
rename to vtm/assets/styles/symbols/petrolStation.png
diff --git a/src/org/oscim/theme/styles/symbols/pharmacy.png b/vtm/assets/styles/symbols/pharmacy.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/pharmacy.png
rename to vtm/assets/styles/symbols/pharmacy.png
diff --git a/src/org/oscim/theme/styles/symbols/playground.png b/vtm/assets/styles/symbols/playground.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/playground.png
rename to vtm/assets/styles/symbols/playground.png
diff --git a/src/org/oscim/theme/styles/symbols/postbox.png b/vtm/assets/styles/symbols/postbox.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/postbox.png
rename to vtm/assets/styles/symbols/postbox.png
diff --git a/src/org/oscim/theme/styles/symbols/postoffice.png b/vtm/assets/styles/symbols/postoffice.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/postoffice.png
rename to vtm/assets/styles/symbols/postoffice.png
diff --git a/src/org/oscim/theme/styles/symbols/pub.png b/vtm/assets/styles/symbols/pub.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/pub.png
rename to vtm/assets/styles/symbols/pub.png
diff --git a/src/org/oscim/theme/styles/symbols/railway-crossing-small.png b/vtm/assets/styles/symbols/railway-crossing-small.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/railway-crossing-small.png
rename to vtm/assets/styles/symbols/railway-crossing-small.png
diff --git a/src/org/oscim/theme/styles/symbols/railway-crossing.png b/vtm/assets/styles/symbols/railway-crossing.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/railway-crossing.png
rename to vtm/assets/styles/symbols/railway-crossing.png
diff --git a/src/org/oscim/theme/styles/symbols/recycling.png b/vtm/assets/styles/symbols/recycling.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/recycling.png
rename to vtm/assets/styles/symbols/recycling.png
diff --git a/src/org/oscim/theme/styles/symbols/restaurant.png b/vtm/assets/styles/symbols/restaurant.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/restaurant.png
rename to vtm/assets/styles/symbols/restaurant.png
diff --git a/src/org/oscim/theme/styles/symbols/school.png b/vtm/assets/styles/symbols/school.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/school.png
rename to vtm/assets/styles/symbols/school.png
diff --git a/src/org/oscim/theme/styles/symbols/shelter.png b/vtm/assets/styles/symbols/shelter.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/shelter.png
rename to vtm/assets/styles/symbols/shelter.png
diff --git a/src/org/oscim/theme/styles/symbols/soccer-borderless.png b/vtm/assets/styles/symbols/soccer-borderless.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/soccer-borderless.png
rename to vtm/assets/styles/symbols/soccer-borderless.png
diff --git a/src/org/oscim/theme/styles/symbols/supermarket.png b/vtm/assets/styles/symbols/supermarket.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/supermarket.png
rename to vtm/assets/styles/symbols/supermarket.png
diff --git a/src/org/oscim/theme/styles/symbols/synagogue.png b/vtm/assets/styles/symbols/synagogue.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/synagogue.png
rename to vtm/assets/styles/symbols/synagogue.png
diff --git a/src/org/oscim/theme/styles/symbols/telephone.png b/vtm/assets/styles/symbols/telephone.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/telephone.png
rename to vtm/assets/styles/symbols/telephone.png
diff --git a/src/org/oscim/theme/styles/symbols/tennis.png b/vtm/assets/styles/symbols/tennis.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/tennis.png
rename to vtm/assets/styles/symbols/tennis.png
diff --git a/src/org/oscim/theme/styles/symbols/theatre.png b/vtm/assets/styles/symbols/theatre.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/theatre.png
rename to vtm/assets/styles/symbols/theatre.png
diff --git a/src/org/oscim/theme/styles/symbols/toilets.png b/vtm/assets/styles/symbols/toilets.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/toilets.png
rename to vtm/assets/styles/symbols/toilets.png
diff --git a/src/org/oscim/theme/styles/symbols/traffic_signal.png b/vtm/assets/styles/symbols/traffic_signal.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/traffic_signal.png
rename to vtm/assets/styles/symbols/traffic_signal.png
diff --git a/src/org/oscim/theme/styles/symbols/tree.png b/vtm/assets/styles/symbols/tree.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/tree.png
rename to vtm/assets/styles/symbols/tree.png
diff --git a/src/org/oscim/theme/styles/symbols/university.png b/vtm/assets/styles/symbols/university.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/university.png
rename to vtm/assets/styles/symbols/university.png
diff --git a/src/org/oscim/theme/styles/symbols/viewpoint.png b/vtm/assets/styles/symbols/viewpoint.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/viewpoint.png
rename to vtm/assets/styles/symbols/viewpoint.png
diff --git a/src/org/oscim/theme/styles/symbols/vulcan.png b/vtm/assets/styles/symbols/vulcan.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/vulcan.png
rename to vtm/assets/styles/symbols/vulcan.png
diff --git a/src/org/oscim/theme/styles/symbols/windmill.png b/vtm/assets/styles/symbols/windmill.png
similarity index 100%
rename from src/org/oscim/theme/styles/symbols/windmill.png
rename to vtm/assets/styles/symbols/windmill.png
diff --git a/src/org/oscim/theme/styles/tronrender.xml b/vtm/assets/styles/tronrender.xml
similarity index 100%
rename from src/org/oscim/theme/styles/tronrender.xml
rename to vtm/assets/styles/tronrender.xml
diff --git a/vtm/jni/Android.mk b/vtm/jni/Android.mk
new file mode 100644
index 00000000..3be634f1
--- /dev/null
+++ b/vtm/jni/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := vtm-jni
+LOCAL_C_INCLUDES := .
+
+LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -O2 -Wall -D__ANDROID__ -Wall -std=c99 -O2 -DTRILIBRARY -DREDUCED -DCDT_ONLY -DNO_TIMER
+LOCAL_CPPFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -O2 -Wall -D__ANDROID__ -Wall -std=c99 -O2 -DTRILIBRARY -DREDUCED -DCDT_ONLY -DNO_TIMER
+LOCAL_LDLIBS := -lm -llog
+LOCAL_ARM_MODE := arm
+
+LOCAL_SRC_FILES := gl/utils.c\
+ triangle/triangle_dbg.c\
+ triangle/TriangleJni.c\
+ triangle/triangle.c
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/vtm/jni/Application.mk b/vtm/jni/Application.mk
new file mode 100644
index 00000000..d0a1e397
--- /dev/null
+++ b/vtm/jni/Application.mk
@@ -0,0 +1 @@
+APP_ABI := armeabi armeabi-v7a
\ No newline at end of file
diff --git a/vtm/jni/build-android32.xml b/vtm/jni/build-android32.xml
new file mode 100644
index 00000000..4487f924
--- /dev/null
+++ b/vtm/jni/build-android32.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ndk_home: ${env.NDK_HOME}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm/jni/build-linux64.xml b/vtm/jni/build-linux64.xml
new file mode 100644
index 00000000..f04435e0
--- /dev/null
+++ b/vtm/jni/build-linux64.xml
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm/jni/build.xml b/vtm/jni/build.xml
new file mode 100644
index 00000000..a4fe3ec1
--- /dev/null
+++ b/vtm/jni/build.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vtm/jni/builder/org/oscim/jni/JniBuilder.java b/vtm/jni/builder/org/oscim/jni/JniBuilder.java
new file mode 100644
index 00000000..db6da38f
--- /dev/null
+++ b/vtm/jni/builder/org/oscim/jni/JniBuilder.java
@@ -0,0 +1,80 @@
+package org.oscim.jni;
+
+
+import com.badlogic.gdx.jnigen.AntScriptGenerator;
+import com.badlogic.gdx.jnigen.BuildConfig;
+import com.badlogic.gdx.jnigen.BuildTarget;
+import com.badlogic.gdx.jnigen.BuildTarget.TargetOs;
+
+public class JniBuilder {
+ public static void main(String[] args) {
+ String[] headers = { "." };
+ String[] sources = { "gl/utils.c", "triangle/TriangleJni.c", "triangle/triangle.c", "triangle/triangle_dbg.c" };
+ String cflags = " -Wall -std=c99 -O2 -DTRILIBRARY -DREDUCED -DCDT_ONLY -DNO_TIMER"; // -Werror";
+
+ BuildTarget win32home = BuildTarget.newDefaultTarget(TargetOs.Windows,
+ false);
+ win32home.compilerPrefix = "";
+ win32home.buildFileName = "build-windows32home.xml";
+ win32home.excludeFromMasterBuildFile = true;
+ win32home.headerDirs = headers;
+ win32home.cIncludes = sources;
+ win32home.cFlags += cflags;
+ win32home.cppFlags += cflags;
+
+ BuildTarget win32 = BuildTarget.newDefaultTarget(TargetOs.Windows,
+ false);
+ win32.headerDirs = headers;
+ win32.cIncludes = sources;
+ win32.cFlags += cflags;
+ win32.cppFlags += cflags;
+
+ BuildTarget win64 = BuildTarget
+ .newDefaultTarget(TargetOs.Windows, true);
+ win64.headerDirs = headers;
+ win64.cIncludes = sources;
+ win64.cFlags += cflags;
+ win64.cppFlags += cflags;
+
+ BuildTarget lin32 = BuildTarget.newDefaultTarget(TargetOs.Linux, false);
+ lin32.headerDirs = headers;
+ lin32.cIncludes = sources;
+ lin32.cFlags += cflags;
+ lin32.cppFlags += cflags;
+
+ BuildTarget lin64 = BuildTarget.newDefaultTarget(TargetOs.Linux, true);
+ lin64.headerDirs = headers;
+ lin64.cIncludes = sources;
+ lin64.cFlags += cflags;
+ lin64.cppFlags += cflags;
+
+ // BuildTarget mac = BuildTarget.newDefaultTarget(TargetOs.MacOsX,
+ // false);
+ // mac.headerDirs = headers;
+ // mac.cIncludes = sources;
+ // mac.cFlags += cflags;
+ // mac.cppFlags += cflags;
+ // mac.linkerFlags += " -framework CoreServices -framework Carbon";
+
+ BuildTarget android = BuildTarget.newDefaultTarget(TargetOs.Android,
+ false);
+ android.headerDirs = headers;
+ android.cIncludes = sources;
+ android.cFlags += cflags;
+ android.cppFlags += cflags;
+ android.linkerFlags += " -llog";
+ // BuildTarget ios = BuildTarget.newDefaultTarget(TargetOs.IOS, false);
+ // ios.headerDirs = headers;
+ // ios.cIncludes = sources;
+ // ios.cFlags += cflags;
+ // ios.cppFlags += cflags;
+
+ //new NativeCodeGenerator().generate();
+ new AntScriptGenerator().generate(new BuildConfig("vtm-jni"),
+ //win32home, win32, win64, lin32,
+ lin64, android);
+// BuildExecutor.executeAnt("jni/build-windows32home.xml", "-v clean");
+// BuildExecutor.executeAnt("jni/build-windows32home.xml", "-v");
+// BuildExecutor.executeAnt("jni/build.xml", "pack-natives -v");
+ }
+}
diff --git a/vtm/jni/gl/utils.c b/vtm/jni/gl/utils.c
new file mode 100644
index 00000000..5ae82195
--- /dev/null
+++ b/vtm/jni/gl/utils.c
@@ -0,0 +1,487 @@
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+//#ifndef uintptr_t
+//typedef unsigned long uintptr_t;
+//#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#if 0
+#ifdef __ANDROID__
+#include
+#include
+#include
+
+#define JNI(X) JNIEXPORT Java_org_oscim_utils_GlUtils_##X
+
+
+#define COLOR_R(C) (((C >> 16) & 0xff) / 255.0f)
+#define COLOR_G(C) (((C >> 8) & 0xff) / 255.0f)
+#define COLOR_B(C) (((C >> 0) & 0xff) / 255.0f)
+#define COLOR_A(C) (((C >> 24) & 0xff) / 255.0f)
+
+void JNI(setColor)(JNIEnv *env, jclass* clazz, jint location, jint c, jfloat alpha)
+{
+
+ if (alpha >= 1)
+ alpha = COLOR_A(c);
+ else if (alpha < 0)
+ alpha = 0;
+ else
+ alpha *= COLOR_A(c);
+
+ if (alpha == 1)
+ {
+ glUniform4f((GLint) location,
+ (GLfloat) COLOR_R(c),
+ (GLfloat) COLOR_G(c),
+ (GLfloat) COLOR_B(c),
+ (GLfloat) alpha);
+ }
+ else
+ {
+ glUniform4f((GLint) location,
+ (GLfloat) (COLOR_R(c) * alpha),
+ (GLfloat) (COLOR_G(c) * alpha),
+ (GLfloat) (COLOR_B(c) * alpha),
+ (GLfloat) alpha);
+ }
+}
+
+void JNI(setColorBlend)(JNIEnv *env, jclass* clazz, jint location, jint c1, jint c2, jfloat mix)
+{
+ float a1 = COLOR_A(c1) * (1 - mix);
+ float a2 = COLOR_A(c2) * mix;
+
+ glUniform4f((GLint) location,
+ (GLfloat) (COLOR_R(c1) * a1 + COLOR_R(c2) * a2),
+ (GLfloat) (COLOR_G(c1) * a1 + COLOR_G(c2) * a2),
+ (GLfloat) (COLOR_B(c1) * a1 + COLOR_B(c2) * a2),
+ (GLfloat) (a1 + a2));
+}
+#endif // __ANDROID__
+#endif // 0
+
+#undef JNI
+#define JNI(X) JNIEXPORT Java_org_oscim_utils_Matrix4_##X
+
+#define CAST(x) (float *)(uintptr_t) x
+#define MAT_SIZE 16 * sizeof(float)
+
+static const float identity[] =
+ { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
+
+static inline void
+multiplyMM(float* r, const float* lhs, const float* rhs);
+
+static inline void
+setRotateM(float* rm, int rmOffset, float a, float x, float y, float z);
+
+static inline void
+transposeM(float* mTrans, int mTransOffset, float* m, int mOffset);
+
+static inline void
+matrix4_proj(float* mat, float* vec);
+
+jlong JNI(alloc)(JNIEnv *env, jclass* clazz)
+{
+ return (long) calloc(16, sizeof(float));
+}
+
+jobject JNI(getBuffer)(JNIEnv *env, jclass* clazz,jlong ptr){
+ return (*env)->NewDirectByteBuffer(env,(char*)(uintptr_t)ptr, 16*sizeof(float));
+}
+
+void JNI(delete)(JNIEnv* env, jclass* clazz, jlong ptr)
+{
+ free(CAST(ptr));
+}
+#if 0
+void JNI(setAsUniform)(JNIEnv* env, jclass* clazz, jlong ptr, jint location)
+{
+ float* m = CAST(ptr);
+
+ glUniformMatrix4fv((GLint) location, (GLsizei) 1, (GLboolean) 0, (GLfloat *) m);
+}
+#endif
+
+void JNI(setValueAt)(JNIEnv* env, jclass* clazz, jlong ptr, jint pos, jfloat value)
+{
+ float* m = CAST(ptr);
+ if (pos > -1 && pos < 16)
+ m[pos] = value;
+}
+
+void JNI(identity)(JNIEnv* env, jclass* clazz, jlong ptr)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+}
+
+void JNI(setScale)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat sx, jfloat sy, jfloat sz)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+ m[0] = sx;
+ m[5] = sy;
+ m[10] = sz;
+}
+
+void JNI(setTranslation)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat x, jfloat y, jfloat z)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+}
+
+void JNI(setRotation)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat a, jfloat x, jfloat y, jfloat z)
+{
+ float* m = CAST(ptr);
+ setRotateM(m, 0, a, x, y, z);
+}
+
+void JNI(setTransScale)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat tx, jfloat ty, jfloat scale)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+ m[0] = scale;
+ m[5] = scale;
+ m[12] = tx;
+ m[13] = ty;
+}
+
+// set matrix from float array
+void JNI(set)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_mat)
+{
+ float* m = CAST(ptr);
+ float* mat = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_mat, 0);
+
+ memcpy(m, mat, MAT_SIZE);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_mat, mat, JNI_ABORT);
+}
+
+// get float array from matrix
+void JNI(get)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_mat)
+{
+ float* m = CAST(ptr);
+ float* mat = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_mat, 0);
+
+ memcpy(mat, m, MAT_SIZE);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_mat, mat, 0);
+}
+
+void JNI(mul)(JNIEnv* env, jclass* clazz, jlong ptr_a, jlong ptr_b)
+{
+ float* mata = CAST(ptr_a);
+ float* matb = CAST(ptr_b);
+
+ multiplyMM(mata, mata, matb);
+}
+
+void JNI(copy)(JNIEnv* env, jclass* clazz, jlong ptr_dst, jlong ptr_src)
+{
+ float* dst = CAST(ptr_dst);
+ float* src = CAST(ptr_src);
+
+ memcpy(dst, src, MAT_SIZE);
+}
+
+void JNI(smul)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_a, jlong ptr_b)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = CAST(ptr_a);
+ float* matb = CAST(ptr_b);
+
+ multiplyMM(matr, mata, matb);
+}
+
+void JNI(smulrhs)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_rhs)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = alloca(16 * sizeof(float));
+ float* matb = CAST(ptr_rhs);
+
+ memcpy(mata, matr, 16 * sizeof(float));
+
+ multiplyMM(matr, mata, matb);
+}
+
+void JNI(smullhs)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_lhs)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = CAST(ptr_lhs);
+ float* matb = alloca(16 * sizeof(float));
+
+ memcpy(matb, matr, 16 * sizeof(float));
+
+ multiplyMM(matr, mata, matb);
+}
+
+
+void JNI(strans)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_a)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = CAST(ptr_a);
+
+ transposeM(matr, 0, mata, 0);
+}
+
+void JNI(prj)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_vec)
+{
+ float* m = CAST(ptr);
+ float* vec = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_vec, 0);
+
+ matrix4_proj(m, vec);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_vec, vec, 0);
+}
+
+static float someRandomEpsilon = 1.0f / (1 << 11);
+
+void JNI(addDepthOffset)(JNIEnv* env, jclass* clazz, jlong ptr, jint delta)
+{
+ float* m = CAST(ptr);
+
+ // from http://www.mathfor3dgameprogramming.com/code/Listing9.1.cpp
+ // float n = MapViewPosition.VIEW_NEAR;
+ // float f = MapViewPosition.VIEW_FAR;
+ // float pz = 1;
+ // float epsilon = -2.0f * f * n * delta / ((f + n) * pz * (pz + delta));
+
+ m[10] *= 1.0f + someRandomEpsilon * delta;
+}
+
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// from android/platform_frameworks_base/blob/master/core/jni/android/opengl/util.cpp
+#define I(_i, _j) ((_j)+ 4*(_i))
+
+static inline void
+multiplyMM(float* r, const float* lhs, const float* rhs)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ register const float rhs_i0 = rhs[I(i,0)];
+ register float ri0 = lhs[I(0,0)] * rhs_i0;
+ register float ri1 = lhs[I(0,1)] * rhs_i0;
+ register float ri2 = lhs[I(0,2)] * rhs_i0;
+ register float ri3 = lhs[I(0,3)] * rhs_i0;
+ for (int j = 1; j < 4; j++)
+ {
+ register const float rhs_ij = rhs[I(i,j)];
+ ri0 += lhs[I(j,0)] * rhs_ij;
+ ri1 += lhs[I(j,1)] * rhs_ij;
+ ri2 += lhs[I(j,2)] * rhs_ij;
+ ri3 += lhs[I(j,3)] * rhs_ij;
+ }
+ r[I(i,0)] = ri0;
+ r[I(i,1)] = ri1;
+ r[I(i,2)] = ri2;
+ r[I(i,3)] = ri3;
+ }
+}
+
+//static inline
+//void
+//mx4transform(float x, float y, float z, float w, const float* pM, float* pDest)
+//{
+// pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
+// pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
+// pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
+//
+// pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
+//}
+
+/**
+ * Computes the length of a vector
+ *
+ * @param x x coordinate of a vector
+ * @param y y coordinate of a vector
+ * @param z z coordinate of a vector
+ * @return the length of a vector
+ */
+static inline float
+length(float x, float y, float z)
+{
+ return (float) sqrt(x * x + y * y + z * z);
+}
+/**
+ * Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
+ * @param rm returns the result
+ * @param rmOffset index into rm where the result matrix starts
+ * @param a angle to rotate in degrees
+ * @param x scale factor x
+ * @param y scale factor y
+ * @param z scale factor z
+ */
+
+static inline void
+setRotateM(float* rm, int rmOffset, float a, float x, float y, float z)
+{
+ rm[rmOffset + 3] = 0;
+ rm[rmOffset + 7] = 0;
+ rm[rmOffset + 11] = 0;
+ rm[rmOffset + 12] = 0;
+ rm[rmOffset + 13] = 0;
+ rm[rmOffset + 14] = 0;
+ rm[rmOffset + 15] = 1;
+ a *= (float) (M_PI / 180.0f);
+ float s = (float) sin(a);
+ float c = (float) cos(a);
+ if (1.0f == x && 0.0f == y && 0.0f == z)
+ {
+ rm[rmOffset + 5] = c;
+ rm[rmOffset + 10] = c;
+ rm[rmOffset + 6] = s;
+ rm[rmOffset + 9] = -s;
+ rm[rmOffset + 1] = 0;
+ rm[rmOffset + 2] = 0;
+ rm[rmOffset + 4] = 0;
+ rm[rmOffset + 8] = 0;
+ rm[rmOffset + 0] = 1;
+ }
+ else if (0.0f == x && 1.0f == y && 0.0f == z)
+ {
+ rm[rmOffset + 0] = c;
+ rm[rmOffset + 10] = c;
+ rm[rmOffset + 8] = s;
+ rm[rmOffset + 2] = -s;
+ rm[rmOffset + 1] = 0;
+ rm[rmOffset + 4] = 0;
+ rm[rmOffset + 6] = 0;
+ rm[rmOffset + 9] = 0;
+ rm[rmOffset + 5] = 1;
+ }
+ else if (0.0f == x && 0.0f == y && 1.0f == z)
+ {
+ rm[rmOffset + 0] = c;
+ rm[rmOffset + 5] = c;
+ rm[rmOffset + 1] = s;
+ rm[rmOffset + 4] = -s;
+ rm[rmOffset + 2] = 0;
+ rm[rmOffset + 6] = 0;
+ rm[rmOffset + 8] = 0;
+ rm[rmOffset + 9] = 0;
+ rm[rmOffset + 10] = 1;
+ }
+ else
+ {
+ float len = length(x, y, z);
+ if (1.0f != len)
+ {
+ float recipLen = 1.0f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ float nc = 1.0f - c;
+ float xy = x * y;
+ float yz = y * z;
+ float zx = z * x;
+ float xs = x * s;
+ float ys = y * s;
+ float zs = z * s;
+ rm[rmOffset + 0] = x * x * nc + c;
+ rm[rmOffset + 4] = xy * nc - zs;
+ rm[rmOffset + 8] = zx * nc + ys;
+ rm[rmOffset + 1] = xy * nc + zs;
+ rm[rmOffset + 5] = y * y * nc + c;
+ rm[rmOffset + 9] = yz * nc - xs;
+ rm[rmOffset + 2] = zx * nc - ys;
+ rm[rmOffset + 6] = yz * nc + xs;
+ rm[rmOffset + 10] = z * z * nc + c;
+ }
+}
+
+/**
+ * Transposes a 4 x 4 matrix.
+ *
+ * @param mTrans the array that holds the output inverted matrix
+ * @param mTransOffset an offset into mInv where the inverted matrix is
+ * stored.
+ * @param m the input array
+ * @param mOffset an offset into m where the matrix is stored.
+ */
+static inline void
+transposeM(float* mTrans, int mTransOffset, float* m, int mOffset)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ int mBase = i * 4 + mOffset;
+ mTrans[i + mTransOffset] = m[mBase];
+ mTrans[i + 4 + mTransOffset] = m[mBase + 1];
+ mTrans[i + 8 + mTransOffset] = m[mBase + 2];
+ mTrans[i + 12 + mTransOffset] = m[mBase + 3];
+ }
+}
+/*******************************************************************************
+ * Copyright 2011 See libgdx AUTHORS file.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+// from /gdx/src/com/badlogic/gdx/math/Matrix4.java
+#define M00 0
+#define M01 4
+#define M02 8
+#define M03 12
+#define M10 1
+#define M11 5
+#define M12 9
+#define M13 13
+#define M20 2
+#define M21 6
+#define M22 10
+#define M23 14
+#define M30 3
+#define M31 7
+#define M32 11
+#define M33 15
+
+static inline void
+matrix4_proj(float* mat, float* vec)
+{
+ float inv_w = 1.0f / (vec[0] * mat[M30] + vec[1] * mat[M31] + vec[2] * mat[M32] + mat[M33]);
+ float x = (vec[0] * mat[M00] + vec[1] * mat[M01] + vec[2] * mat[M02] + mat[M03]) * inv_w;
+ float y = (vec[0] * mat[M10] + vec[1] * mat[M11] + vec[2] * mat[M12] + mat[M13]) * inv_w;
+ float z = (vec[0] * mat[M20] + vec[1] * mat[M21] + vec[2] * mat[M22] + mat[M23]) * inv_w;
+ vec[0] = x;
+ vec[1] = y;
+ vec[2] = z;
+}
diff --git a/vtm/jni/target/linux64/gl/utils.c b/vtm/jni/target/linux64/gl/utils.c
new file mode 100644
index 00000000..5ae82195
--- /dev/null
+++ b/vtm/jni/target/linux64/gl/utils.c
@@ -0,0 +1,487 @@
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+//#ifndef uintptr_t
+//typedef unsigned long uintptr_t;
+//#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#if 0
+#ifdef __ANDROID__
+#include
+#include
+#include
+
+#define JNI(X) JNIEXPORT Java_org_oscim_utils_GlUtils_##X
+
+
+#define COLOR_R(C) (((C >> 16) & 0xff) / 255.0f)
+#define COLOR_G(C) (((C >> 8) & 0xff) / 255.0f)
+#define COLOR_B(C) (((C >> 0) & 0xff) / 255.0f)
+#define COLOR_A(C) (((C >> 24) & 0xff) / 255.0f)
+
+void JNI(setColor)(JNIEnv *env, jclass* clazz, jint location, jint c, jfloat alpha)
+{
+
+ if (alpha >= 1)
+ alpha = COLOR_A(c);
+ else if (alpha < 0)
+ alpha = 0;
+ else
+ alpha *= COLOR_A(c);
+
+ if (alpha == 1)
+ {
+ glUniform4f((GLint) location,
+ (GLfloat) COLOR_R(c),
+ (GLfloat) COLOR_G(c),
+ (GLfloat) COLOR_B(c),
+ (GLfloat) alpha);
+ }
+ else
+ {
+ glUniform4f((GLint) location,
+ (GLfloat) (COLOR_R(c) * alpha),
+ (GLfloat) (COLOR_G(c) * alpha),
+ (GLfloat) (COLOR_B(c) * alpha),
+ (GLfloat) alpha);
+ }
+}
+
+void JNI(setColorBlend)(JNIEnv *env, jclass* clazz, jint location, jint c1, jint c2, jfloat mix)
+{
+ float a1 = COLOR_A(c1) * (1 - mix);
+ float a2 = COLOR_A(c2) * mix;
+
+ glUniform4f((GLint) location,
+ (GLfloat) (COLOR_R(c1) * a1 + COLOR_R(c2) * a2),
+ (GLfloat) (COLOR_G(c1) * a1 + COLOR_G(c2) * a2),
+ (GLfloat) (COLOR_B(c1) * a1 + COLOR_B(c2) * a2),
+ (GLfloat) (a1 + a2));
+}
+#endif // __ANDROID__
+#endif // 0
+
+#undef JNI
+#define JNI(X) JNIEXPORT Java_org_oscim_utils_Matrix4_##X
+
+#define CAST(x) (float *)(uintptr_t) x
+#define MAT_SIZE 16 * sizeof(float)
+
+static const float identity[] =
+ { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
+
+static inline void
+multiplyMM(float* r, const float* lhs, const float* rhs);
+
+static inline void
+setRotateM(float* rm, int rmOffset, float a, float x, float y, float z);
+
+static inline void
+transposeM(float* mTrans, int mTransOffset, float* m, int mOffset);
+
+static inline void
+matrix4_proj(float* mat, float* vec);
+
+jlong JNI(alloc)(JNIEnv *env, jclass* clazz)
+{
+ return (long) calloc(16, sizeof(float));
+}
+
+jobject JNI(getBuffer)(JNIEnv *env, jclass* clazz,jlong ptr){
+ return (*env)->NewDirectByteBuffer(env,(char*)(uintptr_t)ptr, 16*sizeof(float));
+}
+
+void JNI(delete)(JNIEnv* env, jclass* clazz, jlong ptr)
+{
+ free(CAST(ptr));
+}
+#if 0
+void JNI(setAsUniform)(JNIEnv* env, jclass* clazz, jlong ptr, jint location)
+{
+ float* m = CAST(ptr);
+
+ glUniformMatrix4fv((GLint) location, (GLsizei) 1, (GLboolean) 0, (GLfloat *) m);
+}
+#endif
+
+void JNI(setValueAt)(JNIEnv* env, jclass* clazz, jlong ptr, jint pos, jfloat value)
+{
+ float* m = CAST(ptr);
+ if (pos > -1 && pos < 16)
+ m[pos] = value;
+}
+
+void JNI(identity)(JNIEnv* env, jclass* clazz, jlong ptr)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+}
+
+void JNI(setScale)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat sx, jfloat sy, jfloat sz)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+ m[0] = sx;
+ m[5] = sy;
+ m[10] = sz;
+}
+
+void JNI(setTranslation)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat x, jfloat y, jfloat z)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+}
+
+void JNI(setRotation)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat a, jfloat x, jfloat y, jfloat z)
+{
+ float* m = CAST(ptr);
+ setRotateM(m, 0, a, x, y, z);
+}
+
+void JNI(setTransScale)(JNIEnv* env, jclass* clazz, jlong ptr, jfloat tx, jfloat ty, jfloat scale)
+{
+ float* m = CAST(ptr);
+ memcpy(m, identity, MAT_SIZE);
+ m[0] = scale;
+ m[5] = scale;
+ m[12] = tx;
+ m[13] = ty;
+}
+
+// set matrix from float array
+void JNI(set)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_mat)
+{
+ float* m = CAST(ptr);
+ float* mat = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_mat, 0);
+
+ memcpy(m, mat, MAT_SIZE);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_mat, mat, JNI_ABORT);
+}
+
+// get float array from matrix
+void JNI(get)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_mat)
+{
+ float* m = CAST(ptr);
+ float* mat = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_mat, 0);
+
+ memcpy(mat, m, MAT_SIZE);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_mat, mat, 0);
+}
+
+void JNI(mul)(JNIEnv* env, jclass* clazz, jlong ptr_a, jlong ptr_b)
+{
+ float* mata = CAST(ptr_a);
+ float* matb = CAST(ptr_b);
+
+ multiplyMM(mata, mata, matb);
+}
+
+void JNI(copy)(JNIEnv* env, jclass* clazz, jlong ptr_dst, jlong ptr_src)
+{
+ float* dst = CAST(ptr_dst);
+ float* src = CAST(ptr_src);
+
+ memcpy(dst, src, MAT_SIZE);
+}
+
+void JNI(smul)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_a, jlong ptr_b)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = CAST(ptr_a);
+ float* matb = CAST(ptr_b);
+
+ multiplyMM(matr, mata, matb);
+}
+
+void JNI(smulrhs)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_rhs)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = alloca(16 * sizeof(float));
+ float* matb = CAST(ptr_rhs);
+
+ memcpy(mata, matr, 16 * sizeof(float));
+
+ multiplyMM(matr, mata, matb);
+}
+
+void JNI(smullhs)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_lhs)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = CAST(ptr_lhs);
+ float* matb = alloca(16 * sizeof(float));
+
+ memcpy(matb, matr, 16 * sizeof(float));
+
+ multiplyMM(matr, mata, matb);
+}
+
+
+void JNI(strans)(JNIEnv* env, jclass* clazz, jlong ptr_r, jlong ptr_a)
+{
+ float* matr = CAST(ptr_r);
+ float* mata = CAST(ptr_a);
+
+ transposeM(matr, 0, mata, 0);
+}
+
+void JNI(prj)(JNIEnv* env, jclass* clazz, jlong ptr, jfloatArray obj_vec)
+{
+ float* m = CAST(ptr);
+ float* vec = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_vec, 0);
+
+ matrix4_proj(m, vec);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_vec, vec, 0);
+}
+
+static float someRandomEpsilon = 1.0f / (1 << 11);
+
+void JNI(addDepthOffset)(JNIEnv* env, jclass* clazz, jlong ptr, jint delta)
+{
+ float* m = CAST(ptr);
+
+ // from http://www.mathfor3dgameprogramming.com/code/Listing9.1.cpp
+ // float n = MapViewPosition.VIEW_NEAR;
+ // float f = MapViewPosition.VIEW_FAR;
+ // float pz = 1;
+ // float epsilon = -2.0f * f * n * delta / ((f + n) * pz * (pz + delta));
+
+ m[10] *= 1.0f + someRandomEpsilon * delta;
+}
+
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// from android/platform_frameworks_base/blob/master/core/jni/android/opengl/util.cpp
+#define I(_i, _j) ((_j)+ 4*(_i))
+
+static inline void
+multiplyMM(float* r, const float* lhs, const float* rhs)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ register const float rhs_i0 = rhs[I(i,0)];
+ register float ri0 = lhs[I(0,0)] * rhs_i0;
+ register float ri1 = lhs[I(0,1)] * rhs_i0;
+ register float ri2 = lhs[I(0,2)] * rhs_i0;
+ register float ri3 = lhs[I(0,3)] * rhs_i0;
+ for (int j = 1; j < 4; j++)
+ {
+ register const float rhs_ij = rhs[I(i,j)];
+ ri0 += lhs[I(j,0)] * rhs_ij;
+ ri1 += lhs[I(j,1)] * rhs_ij;
+ ri2 += lhs[I(j,2)] * rhs_ij;
+ ri3 += lhs[I(j,3)] * rhs_ij;
+ }
+ r[I(i,0)] = ri0;
+ r[I(i,1)] = ri1;
+ r[I(i,2)] = ri2;
+ r[I(i,3)] = ri3;
+ }
+}
+
+//static inline
+//void
+//mx4transform(float x, float y, float z, float w, const float* pM, float* pDest)
+//{
+// pDest[0] = pM[0 + 4 * 0] * x + pM[0 + 4 * 1] * y + pM[0 + 4 * 2] * z + pM[0 + 4 * 3] * w;
+// pDest[1] = pM[1 + 4 * 0] * x + pM[1 + 4 * 1] * y + pM[1 + 4 * 2] * z + pM[1 + 4 * 3] * w;
+// pDest[2] = pM[2 + 4 * 0] * x + pM[2 + 4 * 1] * y + pM[2 + 4 * 2] * z + pM[2 + 4 * 3] * w;
+//
+// pDest[3] = pM[3 + 4 * 0] * x + pM[3 + 4 * 1] * y + pM[3 + 4 * 2] * z + pM[3 + 4 * 3] * w;
+//}
+
+/**
+ * Computes the length of a vector
+ *
+ * @param x x coordinate of a vector
+ * @param y y coordinate of a vector
+ * @param z z coordinate of a vector
+ * @return the length of a vector
+ */
+static inline float
+length(float x, float y, float z)
+{
+ return (float) sqrt(x * x + y * y + z * z);
+}
+/**
+ * Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
+ * @param rm returns the result
+ * @param rmOffset index into rm where the result matrix starts
+ * @param a angle to rotate in degrees
+ * @param x scale factor x
+ * @param y scale factor y
+ * @param z scale factor z
+ */
+
+static inline void
+setRotateM(float* rm, int rmOffset, float a, float x, float y, float z)
+{
+ rm[rmOffset + 3] = 0;
+ rm[rmOffset + 7] = 0;
+ rm[rmOffset + 11] = 0;
+ rm[rmOffset + 12] = 0;
+ rm[rmOffset + 13] = 0;
+ rm[rmOffset + 14] = 0;
+ rm[rmOffset + 15] = 1;
+ a *= (float) (M_PI / 180.0f);
+ float s = (float) sin(a);
+ float c = (float) cos(a);
+ if (1.0f == x && 0.0f == y && 0.0f == z)
+ {
+ rm[rmOffset + 5] = c;
+ rm[rmOffset + 10] = c;
+ rm[rmOffset + 6] = s;
+ rm[rmOffset + 9] = -s;
+ rm[rmOffset + 1] = 0;
+ rm[rmOffset + 2] = 0;
+ rm[rmOffset + 4] = 0;
+ rm[rmOffset + 8] = 0;
+ rm[rmOffset + 0] = 1;
+ }
+ else if (0.0f == x && 1.0f == y && 0.0f == z)
+ {
+ rm[rmOffset + 0] = c;
+ rm[rmOffset + 10] = c;
+ rm[rmOffset + 8] = s;
+ rm[rmOffset + 2] = -s;
+ rm[rmOffset + 1] = 0;
+ rm[rmOffset + 4] = 0;
+ rm[rmOffset + 6] = 0;
+ rm[rmOffset + 9] = 0;
+ rm[rmOffset + 5] = 1;
+ }
+ else if (0.0f == x && 0.0f == y && 1.0f == z)
+ {
+ rm[rmOffset + 0] = c;
+ rm[rmOffset + 5] = c;
+ rm[rmOffset + 1] = s;
+ rm[rmOffset + 4] = -s;
+ rm[rmOffset + 2] = 0;
+ rm[rmOffset + 6] = 0;
+ rm[rmOffset + 8] = 0;
+ rm[rmOffset + 9] = 0;
+ rm[rmOffset + 10] = 1;
+ }
+ else
+ {
+ float len = length(x, y, z);
+ if (1.0f != len)
+ {
+ float recipLen = 1.0f / len;
+ x *= recipLen;
+ y *= recipLen;
+ z *= recipLen;
+ }
+ float nc = 1.0f - c;
+ float xy = x * y;
+ float yz = y * z;
+ float zx = z * x;
+ float xs = x * s;
+ float ys = y * s;
+ float zs = z * s;
+ rm[rmOffset + 0] = x * x * nc + c;
+ rm[rmOffset + 4] = xy * nc - zs;
+ rm[rmOffset + 8] = zx * nc + ys;
+ rm[rmOffset + 1] = xy * nc + zs;
+ rm[rmOffset + 5] = y * y * nc + c;
+ rm[rmOffset + 9] = yz * nc - xs;
+ rm[rmOffset + 2] = zx * nc - ys;
+ rm[rmOffset + 6] = yz * nc + xs;
+ rm[rmOffset + 10] = z * z * nc + c;
+ }
+}
+
+/**
+ * Transposes a 4 x 4 matrix.
+ *
+ * @param mTrans the array that holds the output inverted matrix
+ * @param mTransOffset an offset into mInv where the inverted matrix is
+ * stored.
+ * @param m the input array
+ * @param mOffset an offset into m where the matrix is stored.
+ */
+static inline void
+transposeM(float* mTrans, int mTransOffset, float* m, int mOffset)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ int mBase = i * 4 + mOffset;
+ mTrans[i + mTransOffset] = m[mBase];
+ mTrans[i + 4 + mTransOffset] = m[mBase + 1];
+ mTrans[i + 8 + mTransOffset] = m[mBase + 2];
+ mTrans[i + 12 + mTransOffset] = m[mBase + 3];
+ }
+}
+/*******************************************************************************
+ * Copyright 2011 See libgdx AUTHORS file.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+// from /gdx/src/com/badlogic/gdx/math/Matrix4.java
+#define M00 0
+#define M01 4
+#define M02 8
+#define M03 12
+#define M10 1
+#define M11 5
+#define M12 9
+#define M13 13
+#define M20 2
+#define M21 6
+#define M22 10
+#define M23 14
+#define M30 3
+#define M31 7
+#define M32 11
+#define M33 15
+
+static inline void
+matrix4_proj(float* mat, float* vec)
+{
+ float inv_w = 1.0f / (vec[0] * mat[M30] + vec[1] * mat[M31] + vec[2] * mat[M32] + mat[M33]);
+ float x = (vec[0] * mat[M00] + vec[1] * mat[M01] + vec[2] * mat[M02] + mat[M03]) * inv_w;
+ float y = (vec[0] * mat[M10] + vec[1] * mat[M11] + vec[2] * mat[M12] + mat[M13]) * inv_w;
+ float z = (vec[0] * mat[M20] + vec[1] * mat[M21] + vec[2] * mat[M22] + mat[M23]) * inv_w;
+ vec[0] = x;
+ vec[1] = y;
+ vec[2] = z;
+}
diff --git a/vtm/jni/target/linux64/triangle/TriangleJni.c b/vtm/jni/target/linux64/triangle/TriangleJni.c
new file mode 100644
index 00000000..56721f3a
--- /dev/null
+++ b/vtm/jni/target/linux64/triangle/TriangleJni.c
@@ -0,0 +1,308 @@
+#include
+#include
+#include
+#include
+#include
+#include "triangle.h"
+
+#ifdef __ANDROID__
+#include
+#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "Triangle", __VA_ARGS__)
+#endif
+
+// from www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
+#if 0
+int pnpoly(int nvert, float *vert, float testx, float testy)
+{
+ int i, j, c = 0;
+ for (i = 0, j = (nvert-1)*2; i < nvert * 2; j = i++)
+ {
+ if ( ((vert[i*2+1] > testy) != (vert[j*j+1] > testy)) &&
+ (testx < (vert[j*2]-vert[i*2])
+ * (testy - vert[i*2+1])
+ / (vert[j*2+1]-vert[i*2+1]) + vert[i*2]) )
+ c = !c;
+ }
+ return c;
+}
+
+int compare_dups(const void *a, const void *b) {
+ int da = *((const long*) a);
+ int db = *((const long*) b);
+ return (da > db) - (da < db);
+}
+
+void shiftSegment(TriangleIO *in, int *seg, int pos) {
+ int size = (in->numberofsegments - pos - 1) * sizeof(int) * 2;
+ printf("shift %d - %d %d\n", size, in->numberofsegments, pos);
+ if (size > 0)
+ memmove(seg, seg + 2, size);
+
+ in->numberofsegments -= 1;
+}
+struct {
+ int p1;
+ int p2;
+} segment;
+
+#endif
+
+static void printPoly(TriangleIO *in) {
+ // print poly format to check with triangle/showme
+ printf("%d 2 0 0\n", in->numberofpoints);
+ for (int j = 0; j < in->numberofpoints; j++)
+ printf("%d %f %f\n", j, in->pointlist[j*2], in->pointlist[j*2+1]);
+
+ int *seg = in->segmentlist;
+ printf("%d 0\n", in->numberofsegments);
+ for (int j = 0; j < in->numberofsegments; j++, seg += 2)
+ printf("%d %d %d\n", j, *seg, *(seg+1));
+
+ printf("%d 0\n", in->numberofholes);
+ for (int j = 0; j < in->numberofholes; j++) {
+ printf("%d %f %f\n", j, in->holelist[j*2], in->holelist[j*2+1]);
+ }
+}
+
+jint Java_org_oscim_renderer_sublayers_ExtrusionLayer_triangulate(JNIEnv *env, jclass c,
+ jfloatArray obj_points, jint pos, jint len, jint num_rings, jobject indice_buf, jint offset) {
+
+ jshort* indices = (jshort*) (*env)->GetDirectBufferAddress(env, indice_buf);
+ jboolean isCopy;
+
+ float* orig_points = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_points, &isCopy);
+ if (orig_points == NULL)
+ return 0;
+
+ float *points = orig_points + pos;
+
+ TriangleIO in, out;
+
+ memset(&in, 0, sizeof(TriangleIO));
+
+ in.numberofpoints = len >> 1;
+ in.pointlist = (float *) points;
+
+ // check if explicitly closed
+ if (in.pointlist[0] == in.pointlist[indices[0] - 2]
+ && in.pointlist[1] == in.pointlist[indices[0] - 1]) {
+ int point = 0;
+ for (int i = 0; i < num_rings; i++) {
+ // remove last point in ring
+ indices[i] -= 2;
+ int last = point + (indices[i] >> 1);
+
+ if (in.numberofpoints - last > 1)
+ memmove(in.pointlist + (last * 2), in.pointlist + ((last + 1) * 2),
+ (in.numberofpoints - last - 1) * 2 * sizeof(float));
+
+ in.numberofpoints--;
+ point = last;
+ }
+ }
+
+ int dups = 0;
+
+ float *i_points = points;
+ int *skip_list = NULL;
+
+ // check for duplicate vertices and keep a list
+ // of dups and the first occurence
+ for (int i = 0; i < in.numberofpoints - 1; i++) {
+ float x = *i_points++;
+ float y = *i_points++;
+ float *j_points = i_points;
+
+ for (int j = i + 1; j < in.numberofpoints; j++, j_points += 2) {
+ if ((*j_points == x) && (*(j_points + 1) == y)) {
+ skip_list = realloc(skip_list, (dups + 2) * 2 * sizeof(int));
+ skip_list[dups * 2 + 0] = j;
+ skip_list[dups * 2 + 1] = i;
+ dups++;
+ }
+ }
+ }
+
+ in.segmentlist = (int *) malloc(in.numberofpoints * 2 * sizeof(int));
+ in.numberofsegments = in.numberofpoints;
+ in.numberofholes = num_rings - 1;
+
+ int *rings = NULL;
+ if (in.numberofholes > 0) {
+ in.holelist = (float *) malloc(in.numberofholes * 2 * sizeof(float));
+ rings = (int*) malloc(num_rings * sizeof(int));
+ }
+
+ int *seg = in.segmentlist;
+ float *hole = in.holelist;
+
+ // counter going through all points
+ int point;
+ // counter going through all rings
+ int ring;
+
+ // assign all points to segments for each ring
+ for (ring = 0, point = 0; ring < num_rings; ring++, point++) {
+ int len;
+ int num_points = indices[ring] >> 1;
+
+ if (rings)
+ rings[ring] = num_points;
+
+ // add holes: we need a point inside the hole...
+ // this is just a heuristic, assuming that two
+ // 'parallel' lines have a distance of at least
+ // 1 unit. you'll notice when things went wrong
+ // when the hole is rendered instead of the poly
+ if (ring > 0) {
+ int k = point * 2;
+
+ float nx = in.pointlist[k++];
+ float ny = in.pointlist[k++];
+
+ float cx = 0, cy = 0, vx = 0, vy = 0;
+
+ // try to find a large enough segment
+ for (len = (point + num_points) * 2; k < len;) {
+ cx = nx;
+ cy = ny;
+
+ nx = in.pointlist[k++];
+ ny = in.pointlist[k++];
+
+ vx = nx - cx;
+ vy = ny - cy;
+
+ if (vx > 4 || vx < -4 || vy > 4 || vy < -4)
+ break;
+ }
+
+ float a = sqrt(vx * vx + vy * vy);
+
+ float ux = -vy / a;
+ float uy = vx / a;
+
+ float centerx = cx + vx / 2.0 - (ux * 0.1);
+ float centery = cy + vy / 2.0 - (uy * 0.1);
+
+ *hole++ = centerx;
+ *hole++ = centery;
+ }
+
+ // close ring
+ int last = point + (num_points - 1);
+ *seg++ = last;
+ *seg++ = point;
+
+ for (len = point + num_points - 1; point < len; point++) {
+ *seg++ = point;
+ *seg++ = point + 1;
+ }
+ }
+
+ if (dups) {
+ for (int i = 0; i < dups; i++) {
+ printf("duplicate points at %d, %d: %f,%f\n",
+ skip_list[i*2], skip_list[i*2+1],
+ in.pointlist[skip_list[i*2+1]*2],
+ in.pointlist[skip_list[i*2+1]*2+1]);
+ }
+ printPoly(&in);
+
+ // replace duplicate positions with first occurence
+ for (int i = 0; i < dups; i++) {
+ // position of the duplicate vertex
+ int pos = skip_list[i * 2] - i;
+ // first vertex
+ int replacement = skip_list[i * 2 + 1];
+
+ seg = in.segmentlist;
+ for (int j = 0; j < in.numberofsegments * 2; j++, seg++) {
+ if (*seg == pos) {
+ printf("%d: %d <- %d", j, pos, replacement);
+ *seg = replacement;
+ }
+ }
+ }
+ }
+
+ memset(&out, 0, sizeof(TriangleIO));
+ out.trianglelist = (INDICE*) indices;
+
+ // p - use polygon input, for CDT
+ // z - zero offset array offsets...
+ // P - no poly output
+ // N - no node output
+ // B - no bound output
+ // Q - be quiet!
+
+ TriangleOptions opt;
+ memset(&opt, 0, sizeof(TriangleOptions));
+
+ opt.dwyer = 1;
+ opt.steiner = -1;
+ opt.order = 1;
+ opt.maxarea = -1.0;
+
+ opt.poly = 1;
+ opt.usesegments = 1;
+ opt.nopolywritten = 1;
+ opt.nonodewritten = 1;
+ opt.nobound = 1;
+ opt.quiet = 1;
+
+ triangulate(&opt, &in, &out, (TriangleIO *) NULL);
+
+ if (in.numberofpoints < out.numberofpoints) {
+ // TODO rerun with 'nonodewritten = 0'
+ printf( "polygon input is bad! points in:%d out%d\n", in.numberofpoints, out.numberofpoints);
+ out.numberoftriangles = 0;
+ }
+ else if (out.trianglelist)
+ {
+ // scale to stride and add offset
+ short stride = 2;
+
+ if (offset < 0)
+ offset = 0;
+
+ INDICE *tri = out.trianglelist;
+
+ for (int n = out.numberoftriangles * 3; n > 0; n--, tri++)
+ *tri = *tri * stride + offset;
+
+ // when a ring has an odd number of points one (or rather two)
+ // additional vertices will be added. so the following rings
+ // needs extra offset...
+ int start = offset;
+ for (int j = 0, m = in.numberofholes; j < m; j++) {
+ start += rings[j] * stride;
+
+ // even number of points?
+ if (!(rings[j] & 1))
+ continue;
+
+ tri = out.trianglelist;
+ int n = out.numberoftriangles * 3;
+
+ for (; n-- > 0; tri++)
+ if (*tri >= start)
+ *tri += stride;
+
+ start += stride;
+ }
+ }
+ else
+ {
+ printf( "triangle failed %d\n", out.numberofpoints);
+ }
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_points, orig_points, JNI_ABORT);
+
+ free(in.segmentlist);
+ free(in.holelist);
+ free(rings);
+ free(skip_list);
+
+ return out.numberoftriangles;
+}
diff --git a/vtm/jni/target/linux64/triangle/triangle.c b/vtm/jni/target/linux64/triangle/triangle.c
new file mode 100644
index 00000000..c4e1a3ca
--- /dev/null
+++ b/vtm/jni/target/linux64/triangle/triangle.c
@@ -0,0 +1,7390 @@
+/*****************************************************************************/
+/* */
+/* 888888888 ,o, / 888 */
+/* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */
+/* 888 888 888 88b 888 888 888 888 888 d888 88b */
+/* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */
+/* 888 888 888 C888 888 888 888 / 888 q888 */
+/* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */
+/* "8oo8D */
+/* */
+/* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */
+/* (triangle.c) */
+/* */
+/* Version 1.6 */
+/* July 28, 2005 */
+/* */
+/* Copyright 1993, 1995, 1997, 1998, 2002, 2005 */
+/* Jonathan Richard Shewchuk */
+/* 2360 Woolsey #H */
+/* Berkeley, California 94705-1927 */
+/* jrs@cs.berkeley.edu */
+/* */
+/* This program may be freely redistributed under the condition that the */
+/* copyright notices (including this entire header and the copyright */
+/* notice printed when the `-h' switch is selected) are not removed, and */
+/* no compensation is received. Private, research, and institutional */
+/* use is free. You may distribute modified versions of this code UNDER */
+/* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */
+/* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */
+/* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */
+/* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */
+/* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */
+/* WITH THE AUTHOR. (If you are not directly supplying this code to a */
+/* customer, and you are instead telling them how they can obtain it for */
+/* free, then you are not required to make any arrangement with me.) */
+/* */
+/* Hypertext instructions for Triangle are available on the Web at */
+/* */
+/* http://www.cs.cmu.edu/~quake/triangle.html */
+/* */
+/* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */
+/* whatsoever. This code is provided "as-is". Use at your own risk. */
+/* */
+/* Some of the references listed below are marked with an asterisk. [*] */
+/* These references are available for downloading from the Web page */
+/* */
+/* http://www.cs.cmu.edu/~quake/triangle.research.html */
+/* */
+/* Three papers discussing aspects of Triangle are available. A short */
+/* overview appears in "Triangle: Engineering a 2D Quality Mesh */
+/* Generator and Delaunay Triangulator," in Applied Computational */
+/* Geometry: Towards Geometric Engineering, Ming C. Lin and Dinesh */
+/* Manocha, editors, Lecture Notes in Computer Science volume 1148, */
+/* pages 203-222, Springer-Verlag, Berlin, May 1996 (from the First ACM */
+/* Workshop on Applied Computational Geometry). [*] */
+/* */
+/* The algorithms are discussed in the greatest detail in "Delaunay */
+/* Refinement Algorithms for Triangular Mesh Generation," Computational */
+/* Geometry: Theory and Applications 22(1-3):21-74, May 2002. [*] */
+/* */
+/* More detail about the data structures may be found in my dissertation: */
+/* "Delaunay Refinement Mesh Generation," Ph.D. thesis, Technical Report */
+/* CMU-CS-97-137, School of Computer Science, Carnegie Mellon University, */
+/* Pittsburgh, Pennsylvania, 18 May 1997. [*] */
+/* */
+/* Triangle was created as part of the Quake Project in the School of */
+/* Computer Science at Carnegie Mellon University. For further */
+/* information, see Hesheng Bao, Jacobo Bielak, Omar Ghattas, Loukas F. */
+/* Kallivokas, David R. O'Hallaron, Jonathan R. Shewchuk, and Jifeng Xu, */
+/* "Large-scale Simulation of Elastic Wave Propagation in Heterogeneous */
+/* Media on Parallel Computers," Computer Methods in Applied Mechanics */
+/* and Engineering 152(1-2):85-102, 22 January 1998. */
+/* */
+/* Triangle's Delaunay refinement algorithm for quality mesh generation is */
+/* a hybrid of one due to Jim Ruppert, "A Delaunay Refinement Algorithm */
+/* for Quality 2-Dimensional Mesh Generation," Journal of Algorithms */
+/* 18(3):548-585, May 1995 [*], and one due to L. Paul Chew, "Guaranteed- */
+/* Quality Mesh Generation for Curved Surfaces," Proceedings of the Ninth */
+/* Annual Symposium on Computational Geometry (San Diego, California), */
+/* pages 274-280, Association for Computing Machinery, May 1993, */
+/* http://portal.acm.org/citation.cfm?id=161150 . */
+/* */
+/* The Delaunay refinement algorithm has been modified so that it meshes */
+/* domains with small input angles well, as described in Gary L. Miller, */
+/* Steven E. Pav, and Noel J. Walkington, "When and Why Ruppert's */
+/* Algorithm Works," Twelfth International Meshing Roundtable, pages */
+/* 91-102, Sandia National Laboratories, September 2003. [*] */
+/* */
+/* My implementation of the divide-and-conquer and incremental Delaunay */
+/* triangulation algorithms follows closely the presentation of Guibas */
+/* and Stolfi, even though I use a triangle-based data structure instead */
+/* of their quad-edge data structure. (In fact, I originally implemented */
+/* Triangle using the quad-edge data structure, but the switch to a */
+/* triangle-based data structure sped Triangle by a factor of two.) The */
+/* mesh manipulation primitives and the two aforementioned Delaunay */
+/* triangulation algorithms are described by Leonidas J. Guibas and Jorge */
+/* Stolfi, "Primitives for the Manipulation of General Subdivisions and */
+/* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */
+/* 4(2):74-123, April 1985, http://portal.acm.org/citation.cfm?id=282923 .*/
+/* */
+/* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */
+/* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */
+/* Delaunay Triangulation," International Journal of Computer and */
+/* Information Science 9(3):219-242, 1980. Triangle's improvement of the */
+/* divide-and-conquer algorithm by alternating between vertical and */
+/* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */
+/* Conquer Algorithm for Constructing Delaunay Triangulations," */
+/* Algorithmica 2(2):137-151, 1987. */
+/* */
+/* The incremental insertion algorithm was first proposed by C. L. Lawson, */
+/* "Software for C1 Surface Interpolation," in Mathematical Software III, */
+/* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */
+/* For point location, I use the algorithm of Ernst P. Mucke, Isaac */
+/* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */
+/* Preprocessing in Two- and Three-Dimensional Delaunay Triangulations," */
+/* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */
+/* ACM, May 1996. [*] If I were to randomize the order of vertex */
+/* insertion (I currently don't bother), their result combined with the */
+/* result of Kenneth L. Clarkson and Peter W. Shor, "Applications of */
+/* Random Sampling in Computational Geometry II," Discrete & */
+/* Computational Geometry 4(1):387-421, 1989, would yield an expected */
+/* O(n^{4/3}) bound on running time. */
+/* */
+/* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */
+/* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */
+/* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */
+/* boundary of the triangulation are maintained in a splay tree for the */
+/* purpose of point location. Splay trees are described by Daniel */
+/* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */
+/* Trees," Journal of the ACM 32(3):652-686, July 1985, */
+/* http://portal.acm.org/citation.cfm?id=3835 . */
+/* */
+/* The algorithms for exact computation of the signs of determinants are */
+/* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */
+/* Point Arithmetic and Fast Robust Geometric Predicates," Discrete & */
+/* Computational Geometry 18(3):305-363, October 1997. (Also available */
+/* as Technical Report CMU-CS-96-140, School of Computer Science, */
+/* Carnegie Mellon University, Pittsburgh, Pennsylvania, May 1996.) [*] */
+/* An abbreviated version appears as Jonathan Richard Shewchuk, "Robust */
+/* Adaptive Floating-Point Geometric Predicates," Proceedings of the */
+/* Twelfth Annual Symposium on Computational Geometry, ACM, May 1996. [*] */
+/* Many of the ideas for my exact arithmetic routines originate with */
+/* Douglas M. Priest, "Algorithms for Arbitrary Precision Floating Point */
+/* Arithmetic," Tenth Symposium on Computer Arithmetic, pp. 132-143, IEEE */
+/* Computer Society Press, 1991. [*] Many of the ideas for the correct */
+/* evaluation of the signs of determinants are taken from Steven Fortune */
+/* and Christopher J. Van Wyk, "Efficient Exact Arithmetic for Computa- */
+/* tional Geometry," Proceedings of the Ninth Annual Symposium on */
+/* Computational Geometry, ACM, pp. 163-172, May 1993, and from Steven */
+/* Fortune, "Numerical Stability of Algorithms for 2D Delaunay Triangu- */
+/* lations," International Journal of Computational Geometry & Applica- */
+/* tions 5(1-2):193-213, March-June 1995. */
+/* */
+/* The method of inserting new vertices off-center (not precisely at the */
+/* circumcenter of every poor-quality triangle) is from Alper Ungor, */
+/* "Off-centers: A New Type of Steiner Points for Computing Size-Optimal */
+/* Quality-Guaranteed Delaunay Triangulations," Proceedings of LATIN */
+/* 2004 (Buenos Aires, Argentina), April 2004. */
+/* */
+/* For definitions of and results involving Delaunay triangulations, */
+/* constrained and conforming versions thereof, and other aspects of */
+/* triangular mesh generation, see the excellent survey by Marshall Bern */
+/* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */
+/* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */
+/* editors, World Scientific, Singapore, pp. 23-90, 1992. [*] */
+/* */
+/* The time for incrementally adding PSLG (planar straight line graph) */
+/* segments to create a constrained Delaunay triangulation is probably */
+/* O(t^2) per segment in the worst case and O(t) per segment in the */
+/* common case, where t is the number of triangles that intersect the */
+/* segment before it is inserted. This doesn't count point location, */
+/* which can be much more expensive. I could improve this to O(d log d) */
+/* time, but d is usually quite small, so it's not worth the bother. */
+/* (This note does not apply when the -s switch is used, invoking a */
+/* different method is used to insert segments.) */
+/* */
+/* The time for deleting a vertex from a Delaunay triangulation is O(d^2) */
+/* in the worst case and O(d) in the common case, where d is the degree */
+/* of the vertex being deleted. I could improve this to O(d log d) time, */
+/* but d is usually quite small, so it's not worth the bother. */
+/* */
+/* Ruppert's Delaunay refinement algorithm typically generates triangles */
+/* at a linear rate (constant time per triangle) after the initial */
+/* triangulation is formed. There may be pathological cases where */
+/* quadratic time is required, but these never arise in practice. */
+/* */
+/* The geometric predicates (circumcenter calculations, segment */
+/* intersection formulae, etc.) appear in my "Lecture Notes on Geometric */
+/* Robustness" at http://www.cs.berkeley.edu/~jrs/mesh . */
+/* */
+/* If you make any improvements to this code, please please please let me */
+/* know, so that I may obtain the improvements. Even if you don't change */
+/* the code, I'd still love to hear what it's being used for. */
+/* */
+/*****************************************************************************/
+
+#include "triangle_private.h"
+
+/* Fast lookup arrays to speed some of the mesh manipulation primitives. */
+
+int plus1mod3[3] = { 1, 2, 0 };
+int minus1mod3[3] = { 2, 0, 1 };
+
+/********* User-defined triangle evaluation routine begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* triunsuitable() Determine if a triangle is unsuitable, and thus must */
+/* be further refined. */
+/* */
+/* You may write your own procedure that decides whether or not a selected */
+/* triangle is too big (and needs to be refined). There are two ways to do */
+/* this. */
+/* */
+/* (1) Modify the procedure `triunsuitable' below, then recompile */
+/* Triangle. */
+/* */
+/* (2) Define the symbol EXTERNAL_TEST (either by adding the definition */
+/* to this file, or by using the appropriate compiler switch). This way, */
+/* you can compile triangle.c separately from your test. Write your own */
+/* `triunsuitable' procedure in a separate C file (using the same prototype */
+/* as below). Compile it and link the object code with triangle.o. */
+/* */
+/* This procedure returns 1 if the triangle is too large and should be */
+/* refined; 0 otherwise. */
+/* */
+/*****************************************************************************/
+
+#ifdef EXTERNAL_TEST
+
+int triunsuitable();
+
+#else /* not EXTERNAL_TEST */
+
+int triunsuitable(vertex triorg, vertex tridest, vertex triapex, REAL area) {
+ REAL dxoa, dxda, dxod;
+ REAL dyoa, dyda, dyod;
+ REAL oalen, dalen, odlen;
+ REAL maxlen;
+
+ dxoa = triorg[0] - triapex[0];
+ dyoa = triorg[1] - triapex[1];
+ dxda = tridest[0] - triapex[0];
+ dyda = tridest[1] - triapex[1];
+ dxod = triorg[0] - tridest[0];
+ dyod = triorg[1] - tridest[1];
+ /* Find the squares of the lengths of the triangle's three edges. */
+ oalen = dxoa * dxoa + dyoa * dyoa;
+ dalen = dxda * dxda + dyda * dyda;
+ odlen = dxod * dxod + dyod * dyod;
+ /* Find the square of the length of the longest edge. */
+ maxlen = (dalen > oalen) ? dalen : oalen;
+ maxlen = (odlen > maxlen) ? odlen : maxlen;
+
+ if (maxlen > 0.05 * (triorg[0] * triorg[0] + triorg[1] * triorg[1]) + 0.02) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+#endif /* not EXTERNAL_TEST */
+
+/** **/
+/** **/
+/********* User-defined triangle evaluation routine ends here *********/
+
+/********* Memory allocation and program exit wrappers begin here *********/
+/** **/
+/** **/
+
+void triexit(int status) {
+ printf("Exit %d.\n", status);
+
+ exit(status);
+}
+
+VOID *trimalloc(int size) {
+ VOID *memptr;
+
+ memptr = (VOID *) malloc((unsigned int) size);
+ if (memptr == (VOID *) NULL) {
+ printf("Error: Out of memory.\n");
+ triexit(1);
+ }
+ return (memptr);
+}
+
+void trifree(VOID *memptr) {
+ free(memptr);
+}
+
+/** **/
+/** **/
+/********* Memory allocation and program exit wrappers end here *********/
+
+/********* User interaction routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* internalerror() Ask the user to send me the defective product. Exit. */
+/* */
+/*****************************************************************************/
+
+int error_set = 0;
+void internalerror() {
+ error_set = 1;
+ printf("Triangle is going to quit its job now\n");
+ //printf(" Please report this bug to jrs@cs.berkeley.edu\n");
+ ///printf(" Include the message above, your input data set, and the exact\n");
+ //printf(" command line you used to run Triangle.\n");
+ //triexit(1);
+}
+
+/*****************************************************************************/
+/* */
+/* parsecommandline() Read the command line, identify switches, and set */
+/* up options and file names. */
+/* */
+/*****************************************************************************/
+
+void parsecommandline(int argc, char **argv, struct behavior *b) {
+ error_set = 0;
+
+#define STARTINDEX 0
+
+ int i, j;
+
+ b->poly = b->refine = b->quality = 0;
+ b->vararea = b->fixedarea = b->usertest = 0;
+ b->regionattrib = b->convex = b->weighted = b->jettison = 0;
+ b->firstnumber = 1;
+ b->edgesout = b->voronoi = b->neighbors = b->geomview = 0;
+ b->nobound = b->nopolywritten = b->nonodewritten = b->noelewritten = 0;
+ b->noiterationnum = 0;
+ b->noholes = b->noexact = 0;
+ b->incremental = b->sweepline = 0;
+ b->dwyer = 1;
+ b->splitseg = 0;
+ b->docheck = 0;
+ b->nobisect = 0;
+ b->conformdel = 0;
+ b->steiner = -1;
+ b->order = 1;
+ b->minangle = 0.0;
+ b->maxarea = -1.0;
+ b->quiet = b->verbose = 0;
+
+ for (i = STARTINDEX; i < argc; i++) {
+ for (j = STARTINDEX; argv[i][j] != '\0'; j++) {
+ if (argv[i][j] == 'p') {
+ b->poly = 1;
+ }
+#ifndef CDT_ONLY
+ if (argv[i][j] == 'r')
+ {
+ b->refine = 1;
+ }
+ if (argv[i][j] == 'q')
+ {
+ b->quality = 1;
+ if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ k = 0;
+ while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ j++;
+ workstring[k] = argv[i][j];
+ k++;
+ }
+ workstring[k] = '\0';
+ b->minangle = (REAL) strtod(workstring, (char **) NULL);
+ }
+ else
+ {
+ b->minangle = 20.0;
+ }
+ }
+ if (argv[i][j] == 'a')
+ {
+ b->quality = 1;
+ if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ b->fixedarea = 1;
+ k = 0;
+ while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ j++;
+ workstring[k] = argv[i][j];
+ k++;
+ }
+ workstring[k] = '\0';
+ b->maxarea = (REAL) strtod(workstring, (char **) NULL);
+ if (b->maxarea <= 0.0)
+ {
+ printf("Error: Maximum area must be greater than zero.\n");
+ triexit(1);
+ }
+ }
+ else
+ {
+ b->vararea = 1;
+ }
+ }
+ if (argv[i][j] == 'u')
+ {
+ b->quality = 1;
+ b->usertest = 1;
+ }
+#endif /* not CDT_ONLY */
+ if (argv[i][j] == 'A') {
+ b->regionattrib = 1;
+ }
+ if (argv[i][j] == 'c') {
+ b->convex = 1;
+ }
+ if (argv[i][j] == 'w') {
+ b->weighted = 1;
+ }
+ if (argv[i][j] == 'W') {
+ b->weighted = 2;
+ }
+ if (argv[i][j] == 'j') {
+ b->jettison = 1;
+ }
+ if (argv[i][j] == 'z') {
+ b->firstnumber = 0;
+ }
+ if (argv[i][j] == 'e') {
+ b->edgesout = 1;
+ }
+ if (argv[i][j] == 'v') {
+ b->voronoi = 1;
+ }
+ if (argv[i][j] == 'n') {
+ b->neighbors = 1;
+ }
+ if (argv[i][j] == 'g') {
+ b->geomview = 1;
+ }
+ if (argv[i][j] == 'B') {
+ b->nobound = 1;
+ }
+ if (argv[i][j] == 'P') {
+ b->nopolywritten = 1;
+ }
+ if (argv[i][j] == 'N') {
+ b->nonodewritten = 1;
+ }
+ if (argv[i][j] == 'E') {
+ b->noelewritten = 1;
+ }
+ if (argv[i][j] == 'O') {
+ b->noholes = 1;
+ }
+ if (argv[i][j] == 'X') {
+ b->noexact = 1;
+ }
+ if (argv[i][j] == 'o') {
+ if (argv[i][j + 1] == '2') {
+ j++;
+ b->order = 2;
+ }
+ }
+#ifndef CDT_ONLY
+ if (argv[i][j] == 'Y')
+ {
+ b->nobisect++;
+ }
+ if (argv[i][j] == 'S')
+ {
+ b->steiner = 0;
+ while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9'))
+ {
+ j++;
+ b->steiner = b->steiner * 10 + (int) (argv[i][j] - '0');
+ }
+ }
+#endif /* not CDT_ONLY */
+#ifndef REDUCED
+ if (argv[i][j] == 'i')
+ {
+ b->incremental = 1;
+ }
+ if (argv[i][j] == 'F')
+ {
+ b->sweepline = 1;
+ }
+#endif /* not REDUCED */
+ if (argv[i][j] == 'l') {
+ b->dwyer = 0;
+ }
+#ifndef REDUCED
+#ifndef CDT_ONLY
+ if (argv[i][j] == 's')
+ {
+ b->splitseg = 1;
+ }
+ if ((argv[i][j] == 'D') || (argv[i][j] == 'L'))
+ {
+ b->quality = 1;
+ b->conformdel = 1;
+ }
+#endif /* not CDT_ONLY */
+ if (argv[i][j] == 'C')
+ {
+ b->docheck = 1;
+ }
+#endif /* not REDUCED */
+ if (argv[i][j] == 'Q') {
+ b->quiet = 1;
+ }
+ if (argv[i][j] == 'V') {
+ b->verbose++;
+ }
+ }
+ }
+ b->usesegments = b->poly || b->refine || b->quality || b->convex;
+ b->goodangle = cos(b->minangle * PI / 180.0);
+ if (b->goodangle == 1.0) {
+ b->offconstant = 0.0;
+ }
+ else {
+ b->offconstant = 0.475 * sqrt((1.0 + b->goodangle) / (1.0 - b->goodangle));
+ }
+ b->goodangle *= b->goodangle;
+ if (b->refine && b->noiterationnum) {
+ printf( "Error: You cannot use the -I switch when refining a triangulation.\n");
+ triexit(1);
+ }
+ /* Be careful not to allocate space for element area constraints that */
+ /* will never be assigned any value (other than the default -1.0). */
+ if (!b->refine && !b->poly) {
+ b->vararea = 0;
+ }
+ /* Be careful not to add an extra attribute to each element unless the */
+ /* input supports it (PSLG in, but not refining a preexisting mesh). */
+ if (b->refine || !b->poly) {
+ b->regionattrib = 0;
+ }
+ /* Regular/weighted triangulations are incompatible with PSLGs */
+ /* and meshing. */
+ if (b->weighted && (b->poly || b->quality)) {
+ b->weighted = 0;
+ if (!b->quiet) {
+ printf("Warning: weighted triangulations (-w, -W) are incompatible\n");
+ printf(" with PSLGs (-p) and meshing (-q, -a, -u). Weights ignored.\n");
+ }
+ }
+ if (b->jettison && b->nonodewritten && !b->quiet) {
+ printf("Warning: -j and -N switches are somewhat incompatible.\n");
+ printf(" If any vertices are jettisoned, you will need the output\n");
+ printf(" .node file to reconstruct the new node indices.");
+ }
+}
+
+/** **/
+/** **/
+/********* User interaction routines begin here *********/
+
+/********* Memory management routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* poolzero() Set all of a pool's fields to zero. */
+/* */
+/* This procedure should never be called on a pool that has any memory */
+/* allocated to it, as that memory would leak. */
+/* */
+/*****************************************************************************/
+
+void poolzero(struct memorypool *pool) {
+ pool->firstblock = (VOID **) NULL;
+ pool->nowblock = (VOID **) NULL;
+ pool->nextitem = (VOID *) NULL;
+ pool->deaditemstack = (VOID *) NULL;
+ pool->pathblock = (VOID **) NULL;
+ pool->pathitem = (VOID *) NULL;
+ pool->alignbytes = 0;
+ pool->itembytes = 0;
+ pool->itemsperblock = 0;
+ pool->itemsfirstblock = 0;
+ pool->items = 0;
+ pool->maxitems = 0;
+ pool->unallocateditems = 0;
+ pool->pathitemsleft = 0;
+}
+
+/*****************************************************************************/
+/* */
+/* poolrestart() Deallocate all items in a pool. */
+/* */
+/* The pool is returned to its starting state, except that no memory is */
+/* freed to the operating system. Rather, the previously allocated blocks */
+/* are ready to be reused. */
+/* */
+/*****************************************************************************/
+
+void poolrestart(struct memorypool *pool) {
+ unsigned long alignptr;
+
+ pool->items = 0;
+ pool->maxitems = 0;
+
+ /* Set the currently active block. */
+ pool->nowblock = pool->firstblock;
+ /* Find the first item in the pool. Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->nowblock + 1);
+ /* Align the item on an `alignbytes'-byte boundary. */
+ pool->nextitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* There are lots of unallocated items left in this block. */
+ pool->unallocateditems = pool->itemsfirstblock;
+ /* The stack of deallocated items is empty. */
+ pool->deaditemstack = (VOID *) NULL;
+}
+
+/*****************************************************************************/
+/* */
+/* poolinit() Initialize a pool of memory for allocation of items. */
+/* */
+/* This routine initializes the machinery for allocating items. A `pool' */
+/* is created whose records have size at least `bytecount'. Items will be */
+/* allocated in `itemcount'-item blocks. Each item is assumed to be a */
+/* collection of words, and either pointers or floating-point values are */
+/* assumed to be the "primary" word type. (The "primary" word type is used */
+/* to determine alignment of items.) If `alignment' isn't zero, all items */
+/* will be `alignment'-byte aligned in memory. `alignment' must be either */
+/* a multiple or a factor of the primary word size; powers of two are safe. */
+/* `alignment' is normally used to create a few unused bits at the bottom */
+/* of each item's pointer, in which information may be stored. */
+/* */
+/* Don't change this routine unless you understand it. */
+/* */
+/*****************************************************************************/
+
+void poolinit(struct memorypool *pool, int bytecount, int itemcount, int firstitemcount,
+ int alignment) {
+ /* Find the proper alignment, which must be at least as large as: */
+ /* - The parameter `alignment'. */
+ /* - sizeof(VOID *), so the stack of dead items can be maintained */
+ /* without unaligned accesses. */
+ if (alignment > sizeof(VOID *)) {
+ pool->alignbytes = alignment;
+ }
+ else {
+ pool->alignbytes = sizeof(VOID *);
+ }
+ pool->itembytes = ((bytecount - 1) / pool->alignbytes + 1) * pool->alignbytes;
+ pool->itemsperblock = itemcount;
+ if (firstitemcount == 0) {
+ pool->itemsfirstblock = itemcount;
+ }
+ else {
+ pool->itemsfirstblock = firstitemcount;
+ }
+
+ /* Allocate a block of items. Space for `itemsfirstblock' items and one */
+ /* pointer (to point to the next block) are allocated, as well as space */
+ /* to ensure alignment of the items. */
+ pool->firstblock = (VOID **) trimalloc(
+ pool->itemsfirstblock * pool->itembytes + (int) sizeof(VOID *) + pool->alignbytes);
+ /* Set the next block pointer to NULL. */
+ *(pool->firstblock) = (VOID *) NULL;
+ poolrestart(pool);
+}
+
+/*****************************************************************************/
+/* */
+/* pooldeinit() Free to the operating system all memory taken by a pool. */
+/* */
+/*****************************************************************************/
+
+void pooldeinit(struct memorypool *pool) {
+ while (pool->firstblock != (VOID **) NULL) {
+ pool->nowblock = (VOID **) *(pool->firstblock);
+ trifree((VOID *) pool->firstblock);
+ pool->firstblock = pool->nowblock;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* poolalloc() Allocate space for an item. */
+/* */
+/*****************************************************************************/
+
+VOID *poolalloc(struct memorypool *pool) {
+ VOID *newitem;
+ VOID **newblock;
+ unsigned long alignptr;
+
+ /* First check the linked list of dead items. If the list is not */
+ /* empty, allocate an item from the list rather than a fresh one. */
+ if (pool->deaditemstack != (VOID *) NULL) {
+ newitem = pool->deaditemstack; /* Take first item in list. */
+ pool->deaditemstack = *(VOID **) pool->deaditemstack;
+ }
+ else {
+ /* Check if there are any free items left in the current block. */
+ if (pool->unallocateditems == 0) {
+ /* Check if another block must be allocated. */
+ if (*(pool->nowblock) == (VOID *) NULL) {
+ /* Allocate a new block of items, pointed to by the previous block. */
+ newblock = (VOID **) trimalloc(
+ pool->itemsperblock * pool->itembytes + (int) sizeof(VOID *) + pool->alignbytes);
+ *(pool->nowblock) = (VOID *) newblock;
+ /* The next block pointer is NULL. */
+ *newblock = (VOID *) NULL;
+ }
+
+ /* Move to the new block. */
+ pool->nowblock = (VOID **) *(pool->nowblock);
+ /* Find the first item in the block. */
+ /* Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->nowblock + 1);
+ /* Align the item on an `alignbytes'-byte boundary. */
+ pool->nextitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* There are lots of unallocated items left in this block. */
+ pool->unallocateditems = pool->itemsperblock;
+ }
+
+ /* Allocate a new item. */
+ newitem = pool->nextitem;
+ /* Advance `nextitem' pointer to next free item in block. */
+ pool->nextitem = (VOID *) ((char *) pool->nextitem + pool->itembytes);
+ pool->unallocateditems--;
+ pool->maxitems++;
+ }
+ pool->items++;
+ return newitem;
+}
+
+/*****************************************************************************/
+/* */
+/* pooldealloc() Deallocate space for an item. */
+/* */
+/* The deallocated space is stored in a queue for later reuse. */
+/* */
+/*****************************************************************************/
+
+void pooldealloc(struct memorypool *pool, VOID *dyingitem) {
+ /* Push freshly killed item onto stack. */
+ *((VOID **) dyingitem) = pool->deaditemstack;
+ pool->deaditemstack = dyingitem;
+ pool->items--;
+}
+
+/*****************************************************************************/
+/* */
+/* traversalinit() Prepare to traverse the entire list of items. */
+/* */
+/* This routine is used in conjunction with traverse(). */
+/* */
+/*****************************************************************************/
+
+void traversalinit(struct memorypool *pool) {
+ unsigned long alignptr;
+
+ /* Begin the traversal in the first block. */
+ pool->pathblock = pool->firstblock;
+ /* Find the first item in the block. Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->pathblock + 1);
+ /* Align with item on an `alignbytes'-byte boundary. */
+ pool->pathitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* Set the number of items left in the current block. */
+ pool->pathitemsleft = pool->itemsfirstblock;
+}
+
+/*****************************************************************************/
+/* */
+/* traverse() Find the next item in the list. */
+/* */
+/* This routine is used in conjunction with traversalinit(). Be forewarned */
+/* that this routine successively returns all items in the list, including */
+/* deallocated ones on the deaditemqueue. It's up to you to figure out */
+/* which ones are actually dead. Why? I don't want to allocate extra */
+/* space just to demarcate dead items. It can usually be done more */
+/* space-efficiently by a routine that knows something about the structure */
+/* of the item. */
+/* */
+/*****************************************************************************/
+
+VOID *traverse(struct memorypool *pool) {
+ VOID *newitem;
+ unsigned long alignptr;
+
+ /* Stop upon exhausting the list of items. */
+ if (pool->pathitem == pool->nextitem) {
+ return (VOID *) NULL;
+ }
+
+ /* Check whether any untraversed items remain in the current block. */
+ if (pool->pathitemsleft == 0) {
+ /* Find the next block. */
+ pool->pathblock = (VOID **) *(pool->pathblock);
+ /* Find the first item in the block. Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->pathblock + 1);
+ /* Align with item on an `alignbytes'-byte boundary. */
+ pool->pathitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* Set the number of items left in the current block. */
+ pool->pathitemsleft = pool->itemsperblock;
+ }
+
+ newitem = pool->pathitem;
+ /* Find the next item in the block. */
+ pool->pathitem = (VOID *) ((char *) pool->pathitem + pool->itembytes);
+ pool->pathitemsleft--;
+ return newitem;
+}
+
+/*****************************************************************************/
+/* */
+/* dummyinit() Initialize the triangle that fills "outer space" and the */
+/* omnipresent subsegment. */
+/* */
+/* The triangle that fills "outer space," called `dummytri', is pointed to */
+/* by every triangle and subsegment on a boundary (be it outer or inner) of */
+/* the triangulation. Also, `dummytri' points to one of the triangles on */
+/* the convex hull (until the holes and concavities are carved), making it */
+/* possible to find a starting triangle for point location. */
+/* */
+/* The omnipresent subsegment, `dummysub', is pointed to by every triangle */
+/* or subsegment that doesn't have a full complement of real subsegments */
+/* to point to. */
+/* */
+/* `dummytri' and `dummysub' are generally required to fulfill only a few */
+/* invariants: their vertices must remain NULL and `dummytri' must always */
+/* be bonded (at offset zero) to some triangle on the convex hull of the */
+/* mesh, via a boundary edge. Otherwise, the connections of `dummytri' and */
+/* `dummysub' may change willy-nilly. This makes it possible to avoid */
+/* writing a good deal of special-case code (in the edge flip, for example) */
+/* for dealing with the boundary of the mesh, places where no subsegment is */
+/* present, and so forth. Other entities are frequently bonded to */
+/* `dummytri' and `dummysub' as if they were real mesh entities, with no */
+/* harm done. */
+/* */
+/*****************************************************************************/
+
+void dummyinit(struct mesh *m, struct behavior *b, int trianglebytes, int subsegbytes) {
+ unsigned long alignptr;
+
+ /* Set up `dummytri', the `triangle' that occupies "outer space." */
+ m->dummytribase = (triangle *) trimalloc(trianglebytes + m->triangles.alignbytes);
+ /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */
+ alignptr = (unsigned long) m->dummytribase;
+ m->dummytri = (triangle *) (alignptr + (unsigned long) m->triangles.alignbytes
+ - (alignptr % (unsigned long) m->triangles.alignbytes));
+ /* Initialize the three adjoining triangles to be "outer space." These */
+ /* will eventually be changed by various bonding operations, but their */
+ /* values don't really matter, as long as they can legally be */
+ /* dereferenced. */
+ m->dummytri[0] = (triangle) m->dummytri;
+ m->dummytri[1] = (triangle) m->dummytri;
+ m->dummytri[2] = (triangle) m->dummytri;
+ /* Three NULL vertices. */
+ m->dummytri[3] = (triangle) NULL;
+ m->dummytri[4] = (triangle) NULL;
+ m->dummytri[5] = (triangle) NULL;
+
+ if (b->usesegments) {
+ /* Set up `dummysub', the omnipresent subsegment pointed to by any */
+ /* triangle side or subsegment end that isn't attached to a real */
+ /* subsegment. */
+ m->dummysubbase = (subseg *) trimalloc(subsegbytes + m->subsegs.alignbytes);
+ /* Align `dummysub' on a `subsegs.alignbytes'-byte boundary. */
+ alignptr = (unsigned long) m->dummysubbase;
+ m->dummysub = (subseg *) (alignptr + (unsigned long) m->subsegs.alignbytes
+ - (alignptr % (unsigned long) m->subsegs.alignbytes));
+ /* Initialize the two adjoining subsegments to be the omnipresent */
+ /* subsegment. These will eventually be changed by various bonding */
+ /* operations, but their values don't really matter, as long as they */
+ /* can legally be dereferenced. */
+ m->dummysub[0] = (subseg) m->dummysub;
+ m->dummysub[1] = (subseg) m->dummysub;
+ /* Four NULL vertices. */
+ m->dummysub[2] = (subseg) NULL;
+ m->dummysub[3] = (subseg) NULL;
+ m->dummysub[4] = (subseg) NULL;
+ m->dummysub[5] = (subseg) NULL;
+ /* Initialize the two adjoining triangles to be "outer space." */
+ m->dummysub[6] = (subseg) m->dummytri;
+ m->dummysub[7] = (subseg) m->dummytri;
+ /* Set the boundary marker to zero. */
+ *(int *) (m->dummysub + 8) = 0;
+
+ /* Initialize the three adjoining subsegments of `dummytri' to be */
+ /* the omnipresent subsegment. */
+ m->dummytri[6] = (triangle) m->dummysub;
+ m->dummytri[7] = (triangle) m->dummysub;
+ m->dummytri[8] = (triangle) m->dummysub;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* initializevertexpool() Calculate the size of the vertex data structure */
+/* and initialize its memory pool. */
+/* */
+/* This routine also computes the `vertexmarkindex' and `vertex2triindex' */
+/* indices used to find values within each vertex. */
+/* */
+/*****************************************************************************/
+
+void initializevertexpool(struct mesh *m, struct behavior *b) {
+ int vertexsize;
+
+ /* The index within each vertex at which the boundary marker is found, */
+ /* followed by the vertex type. Ensure the vertex marker is aligned to */
+ /* a sizeof(int)-byte address. */
+ m->vertexmarkindex = ((m->mesh_dim + m->nextras) * sizeof(REAL) + sizeof(int) - 1) / sizeof(int);
+ vertexsize = (m->vertexmarkindex + 2) * sizeof(int);
+ if (b->poly) {
+ /* The index within each vertex at which a triangle pointer is found. */
+ /* Ensure the pointer is aligned to a sizeof(triangle)-byte address. */
+ m->vertex2triindex = (vertexsize + sizeof(triangle) - 1) / sizeof(triangle);
+ vertexsize = (m->vertex2triindex + 1) * sizeof(triangle);
+ }
+
+ /* Initialize the pool of vertices. */
+ poolinit(&m->vertices, vertexsize, VERTEXPERBLOCK,
+ m->invertices > VERTEXPERBLOCK ? m->invertices : VERTEXPERBLOCK,
+ sizeof(REAL));
+}
+
+/*****************************************************************************/
+/* */
+/* initializetrisubpools() Calculate the sizes of the triangle and */
+/* subsegment data structures and initialize */
+/* their memory pools. */
+/* */
+/* This routine also computes the `highorderindex', `elemattribindex', and */
+/* `areaboundindex' indices used to find values within each triangle. */
+/* */
+/*****************************************************************************/
+
+void initializetrisubpools(struct mesh *m, struct behavior *b) {
+ int trisize;
+
+ /* The index within each triangle at which the extra nodes (above three) */
+ /* associated with high order elements are found. There are three */
+ /* pointers to other triangles, three pointers to corners, and possibly */
+ /* three pointers to subsegments before the extra nodes. */
+ m->highorderindex = 6 + (b->usesegments * 3);
+ /* The number of bytes occupied by a triangle. */
+ trisize = ((b->order + 1) * (b->order + 2) / 2 + (m->highorderindex - 3)) * sizeof(triangle);
+ /* The index within each triangle at which its attributes are found, */
+ /* where the index is measured in REALs. */
+ m->elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL);
+ /* The index within each triangle at which the maximum area constraint */
+ /* is found, where the index is measured in REALs. Note that if the */
+ /* `regionattrib' flag is set, an additional attribute will be added. */
+ m->areaboundindex = m->elemattribindex + m->eextras + b->regionattrib;
+ /* If triangle attributes or an area bound are needed, increase the number */
+ /* of bytes occupied by a triangle. */
+ if (b->vararea) {
+ trisize = (m->areaboundindex + 1) * sizeof(REAL);
+ }
+ else if (m->eextras + b->regionattrib > 0) {
+ trisize = m->areaboundindex * sizeof(REAL);
+ }
+ /* If a Voronoi diagram or triangle neighbor graph is requested, make */
+ /* sure there's room to store an integer index in each triangle. This */
+ /* integer index can occupy the same space as the subsegment pointers */
+ /* or attributes or area constraint or extra nodes. */
+ if ((b->voronoi || b->neighbors) && (trisize < 6 * sizeof(triangle) + sizeof(int))) {
+ trisize = 6 * sizeof(triangle) + sizeof(int);
+ }
+
+ /* Having determined the memory size of a triangle, initialize the pool. */
+ poolinit(&m->triangles, trisize, TRIPERBLOCK,
+ (2 * m->invertices - 2) > TRIPERBLOCK ? (2 * m->invertices - 2) : TRIPERBLOCK, 4);
+
+ if (b->usesegments) {
+ /* Initialize the pool of subsegments. Take into account all eight */
+ /* pointers and one boundary marker. */
+ poolinit(&m->subsegs, 8 * sizeof(triangle) + sizeof(int), SUBSEGPERBLOCK, SUBSEGPERBLOCK, 4);
+
+ /* Initialize the "outer space" triangle and omnipresent subsegment. */
+ dummyinit(m, b, m->triangles.itembytes, m->subsegs.itembytes);
+ }
+ else {
+ /* Initialize the "outer space" triangle. */
+ dummyinit(m, b, m->triangles.itembytes, 0);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* triangledealloc() Deallocate space for a triangle, marking it dead. */
+/* */
+/*****************************************************************************/
+
+void triangledealloc(struct mesh *m, triangle *dyingtriangle) {
+ /* Mark the triangle as dead. This makes it possible to detect dead */
+ /* triangles when traversing the list of all triangles. */
+ killtri(dyingtriangle);
+ pooldealloc(&m->triangles, (VOID *) dyingtriangle);
+}
+
+/*****************************************************************************/
+/* */
+/* triangletraverse() Traverse the triangles, skipping dead ones. */
+/* */
+/*****************************************************************************/
+
+triangle *triangletraverse(struct mesh *m) {
+ triangle *newtriangle;
+
+ do {
+ newtriangle = (triangle *) traverse(&m->triangles);
+ if (newtriangle == (triangle *) NULL) {
+ return (triangle *) NULL;
+ }
+ } while (deadtri(newtriangle)); /* Skip dead ones. */
+ return newtriangle;
+}
+
+/*****************************************************************************/
+/* */
+/* subsegdealloc() Deallocate space for a subsegment, marking it dead. */
+/* */
+/*****************************************************************************/
+
+void subsegdealloc(struct mesh *m, subseg *dyingsubseg) {
+ /* Mark the subsegment as dead. This makes it possible to detect dead */
+ /* subsegments when traversing the list of all subsegments. */
+ killsubseg(dyingsubseg);
+ pooldealloc(&m->subsegs, (VOID *) dyingsubseg);
+}
+
+/*****************************************************************************/
+/* */
+/* subsegtraverse() Traverse the subsegments, skipping dead ones. */
+/* */
+/*****************************************************************************/
+
+subseg *subsegtraverse(struct mesh *m) {
+ subseg *newsubseg;
+
+ do {
+ newsubseg = (subseg *) traverse(&m->subsegs);
+ if (newsubseg == (subseg *) NULL) {
+ return (subseg *) NULL;
+ }
+ } while (deadsubseg(newsubseg)); /* Skip dead ones. */
+ return newsubseg;
+}
+
+/*****************************************************************************/
+/* */
+/* vertexdealloc() Deallocate space for a vertex, marking it dead. */
+/* */
+/*****************************************************************************/
+
+void vertexdealloc(struct mesh *m, vertex dyingvertex) {
+ /* Mark the vertex as dead. This makes it possible to detect dead */
+ /* vertices when traversing the list of all vertices. */
+ setvertextype(dyingvertex, DEADVERTEX);
+ pooldealloc(&m->vertices, (VOID *) dyingvertex);
+}
+
+/*****************************************************************************/
+/* */
+/* vertextraverse() Traverse the vertices, skipping dead ones. */
+/* */
+/*****************************************************************************/
+
+vertex vertextraverse(struct mesh *m) {
+ vertex newvertex;
+
+ do {
+ newvertex = (vertex) traverse(&m->vertices);
+ if (newvertex == (vertex) NULL) {
+ return (vertex) NULL;
+ }
+ } while (vertextype(newvertex) == DEADVERTEX); /* Skip dead ones. */
+ return newvertex;
+}
+
+/*****************************************************************************/
+/* */
+/* getvertex() Get a specific vertex, by number, from the list. */
+/* */
+/* The first vertex is number 'firstnumber'. */
+/* */
+/* Note that this takes O(n) time (with a small constant, if VERTEXPERBLOCK */
+/* is large). I don't care to take the trouble to make it work in constant */
+/* time. */
+/* */
+/*****************************************************************************/
+
+vertex getvertex(struct mesh *m, struct behavior *b, int number) {
+ VOID **getblock;
+ char *foundvertex;
+ unsigned long alignptr;
+ int current;
+
+ getblock = m->vertices.firstblock;
+ current = b->firstnumber;
+
+ /* Find the right block. */
+ if (current + m->vertices.itemsfirstblock <= number) {
+ getblock = (VOID **) *getblock;
+ current += m->vertices.itemsfirstblock;
+ while (current + m->vertices.itemsperblock <= number) {
+ getblock = (VOID **) *getblock;
+ current += m->vertices.itemsperblock;
+ }
+ }
+
+ /* Now find the right vertex. */
+ alignptr = (unsigned long) (getblock + 1);
+ foundvertex = (char *) (alignptr + (unsigned long) m->vertices.alignbytes
+ - (alignptr % (unsigned long) m->vertices.alignbytes));
+ return (vertex) (foundvertex + m->vertices.itembytes * (number - current));
+}
+
+/*****************************************************************************/
+/* */
+/* triangledeinit() Free all remaining allocated memory. */
+/* */
+/*****************************************************************************/
+
+void triangledeinit(struct mesh *m, struct behavior *b) {
+ pooldeinit(&m->triangles);
+ trifree((VOID *) m->dummytribase);
+ if (b->usesegments) {
+ pooldeinit(&m->subsegs);
+ trifree((VOID *) m->dummysubbase);
+ }
+ pooldeinit(&m->vertices);
+#ifndef CDT_ONLY
+ if (b->quality)
+ {
+ pooldeinit(&m->badsubsegs);
+ if ((b->minangle > 0.0) || b->vararea || b->fixedarea || b->usertest)
+ {
+ pooldeinit(&m->badtriangles);
+ pooldeinit(&m->flipstackers);
+ }
+ }
+#endif /* not CDT_ONLY */
+}
+
+/** **/
+/** **/
+/********* Memory management routines end here *********/
+
+/********* Constructors begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* maketriangle() Create a new triangle with orientation zero. */
+/* */
+/*****************************************************************************/
+
+void maketriangle(struct mesh *m, struct behavior *b, struct otri *newotri) {
+ int i;
+
+ newotri->tri = (triangle *) poolalloc(&m->triangles);
+ /* Initialize the three adjoining triangles to be "outer space". */
+ newotri->tri[0] = (triangle) m->dummytri;
+ newotri->tri[1] = (triangle) m->dummytri;
+ newotri->tri[2] = (triangle) m->dummytri;
+ /* Three NULL vertices. */
+ newotri->tri[3] = (triangle) NULL;
+ newotri->tri[4] = (triangle) NULL;
+ newotri->tri[5] = (triangle) NULL;
+ if (b->usesegments) {
+ /* Initialize the three adjoining subsegments to be the omnipresent */
+ /* subsegment. */
+ newotri->tri[6] = (triangle) m->dummysub;
+ newotri->tri[7] = (triangle) m->dummysub;
+ newotri->tri[8] = (triangle) m->dummysub;
+ }
+ for (i = 0; i < m->eextras; i++) {
+ setelemattribute(*newotri, i, 0.0);
+ }
+ if (b->vararea) {
+ setareabound(*newotri, -1.0);
+ }
+
+ newotri->orient = 0;
+}
+
+/*****************************************************************************/
+/* */
+/* makesubseg() Create a new subsegment with orientation zero. */
+/* */
+/*****************************************************************************/
+
+void makesubseg(struct mesh *m, struct osub *newsubseg) {
+ newsubseg->ss = (subseg *) poolalloc(&m->subsegs);
+ /* Initialize the two adjoining subsegments to be the omnipresent */
+ /* subsegment. */
+ newsubseg->ss[0] = (subseg) m->dummysub;
+ newsubseg->ss[1] = (subseg) m->dummysub;
+ /* Four NULL vertices. */
+ newsubseg->ss[2] = (subseg) NULL;
+ newsubseg->ss[3] = (subseg) NULL;
+ newsubseg->ss[4] = (subseg) NULL;
+ newsubseg->ss[5] = (subseg) NULL;
+ /* Initialize the two adjoining triangles to be "outer space." */
+ newsubseg->ss[6] = (subseg) m->dummytri;
+ newsubseg->ss[7] = (subseg) m->dummytri;
+ /* Set the boundary marker to zero. */
+ setmark(*newsubseg, 0);
+
+ newsubseg->ssorient = 0;
+}
+
+/** **/
+/** **/
+/********* Constructors end here *********/
+
+/********* Geometric primitives begin here *********/
+/** **/
+/** **/
+
+/* The adaptive exact arithmetic geometric predicates implemented herein are */
+/* described in detail in my paper, "Adaptive Precision Floating-Point */
+/* Arithmetic and Fast Robust Geometric Predicates." See the header for a */
+/* full citation. */
+
+/* Which of the following two methods of finding the absolute values is */
+/* fastest is compiler-dependent. A few compilers can inline and optimize */
+/* the fabs() call; but most will incur the overhead of a function call, */
+/* which is disastrously slow. A faster way on IEEE machines might be to */
+/* mask the appropriate bit, but that's difficult to do in C without */
+/* forcing the value to be stored to memory (rather than be kept in the */
+/* register to which the optimizer assigned it). */
+
+#define Absolute(a) ((a) >= 0.0 ? (a) : -(a))
+/* #define Absolute(a) fabs(a) */
+
+/* Many of the operations are broken up into two pieces, a main part that */
+/* performs an approximate operation, and a "tail" that computes the */
+/* roundoff error of that operation. */
+/* */
+/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */
+/* Split(), and Two_Product() are all implemented as described in the */
+/* reference. Each of these macros requires certain variables to be */
+/* defined in the calling routine. The variables `bvirt', `c', `abig', */
+/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `' because */
+/* they store the result of an operation that may incur roundoff error. */
+/* The input parameter `x' (or the highest numbered `x_' parameter) must */
+/* also be declared `'. */
+
+#define Fast_Two_Sum_Tail(a, b, x, y) \
+ bvirt = x - a; \
+ y = b - bvirt
+
+#define Fast_Two_Sum(a, b, x, y) \
+ x = (REAL) (a + b); \
+ Fast_Two_Sum_Tail(a, b, x, y)
+
+#define Two_Sum_Tail(a, b, x, y) \
+ bvirt = (REAL) (x - a); \
+ avirt = x - bvirt; \
+ bround = b - bvirt; \
+ around = a - avirt; \
+ y = around + bround
+
+#define Two_Sum(a, b, x, y) \
+ x = (REAL) (a + b); \
+ Two_Sum_Tail(a, b, x, y)
+
+#define Two_Diff_Tail(a, b, x, y) \
+ bvirt = (REAL) (a - x); \
+ avirt = x + bvirt; \
+ bround = bvirt - b; \
+ around = a - avirt; \
+ y = around + bround
+
+#define Two_Diff(a, b, x, y) \
+ x = (REAL) (a - b); \
+ Two_Diff_Tail(a, b, x, y)
+
+#define Split(a, ahi, alo) \
+ c = (REAL) (splitter * a); \
+ abig = (REAL) (c - a); \
+ ahi = c - abig; \
+ alo = a - ahi
+
+#define Two_Product_Tail(a, b, x, y) \
+ Split(a, ahi, alo); \
+ Split(b, bhi, blo); \
+ err1 = x - (ahi * bhi); \
+ err2 = err1 - (alo * bhi); \
+ err3 = err2 - (ahi * blo); \
+ y = (alo * blo) - err3
+
+#define Two_Product(a, b, x, y) \
+ x = (REAL) (a * b); \
+ Two_Product_Tail(a, b, x, y)
+
+/* Two_Product_Presplit() is Two_Product() where one of the inputs has */
+/* already been split. Avoids redundant splitting. */
+
+#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
+ x = (REAL) (a * b); \
+ Split(a, ahi, alo); \
+ err1 = x - (ahi * bhi); \
+ err2 = err1 - (alo * bhi); \
+ err3 = err2 - (ahi * blo); \
+ y = (alo * blo) - err3
+
+/* Square() can be done more quickly than Two_Product(). */
+
+#define Square_Tail(a, x, y) \
+ Split(a, ahi, alo); \
+ err1 = x - (ahi * ahi); \
+ err3 = err1 - ((ahi + ahi) * alo); \
+ y = (alo * alo) - err3
+
+#define Square(a, x, y) \
+ x = (REAL) (a * a); \
+ Square_Tail(a, x, y)
+
+/* Macros for summing expansions of various fixed lengths. These are all */
+/* unrolled versions of Expansion_Sum(). */
+
+#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
+ Two_Sum(a0, b , _i, x0); \
+ Two_Sum(a1, _i, x2, x1)
+
+#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
+ Two_Diff(a0, b , _i, x0); \
+ Two_Sum( a1, _i, x2, x1)
+
+#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
+ Two_One_Sum(a1, a0, b0, _j, _0, x0); \
+ Two_One_Sum(_j, _0, b1, x3, x2, x1)
+
+#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
+ Two_One_Diff(a1, a0, b0, _j, _0, x0); \
+ Two_One_Diff(_j, _0, b1, x3, x2, x1)
+
+/* Macro for multiplying a two-component expansion by a single component. */
+
+#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \
+ Split(b, bhi, blo); \
+ Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
+ Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
+ Two_Sum(_i, _0, _k, x1); \
+ Fast_Two_Sum(_j, _k, x3, x2)
+
+/*****************************************************************************/
+/* */
+/* exactinit() Initialize the variables used for exact arithmetic. */
+/* */
+/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */
+/* floating-point arithmetic. `epsilon' bounds the relative roundoff */
+/* error. It is used for floating-point error analysis. */
+/* */
+/* `splitter' is used to split floating-point numbers into two half- */
+/* length significands for exact multiplication. */
+/* */
+/* I imagine that a highly optimizing compiler might be too smart for its */
+/* own good, and somehow cause this routine to fail, if it pretends that */
+/* floating-point arithmetic is too much like real arithmetic. */
+/* */
+/* Don't change this routine unless you fully understand it. */
+/* */
+/*****************************************************************************/
+
+void exactinit() {
+ REAL half;
+ REAL check, lastcheck;
+ int every_other;
+#ifdef LINUX
+ int cword;
+#endif /* LINUX */
+
+#ifdef CPU86
+#ifdef SINGLE
+ _control87(_PC_24, _MCW_PC); /* Set FPU control word for single precision. */
+#else /* not SINGLE */
+ _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */
+#endif /* not SINGLE */
+#endif /* CPU86 */
+#ifdef LINUX
+#ifdef SINGLE
+ /* cword = 4223; */
+ cword = 4210; /* set FPU control word for single precision */
+#else /* not SINGLE */
+ /* cword = 4735; */
+ cword = 4722; /* set FPU control word for double precision */
+#endif /* not SINGLE */
+ _FPU_SETCW(cword);
+#endif /* LINUX */
+
+ every_other = 1;
+ half = 0.5;
+ epsilon = 1.0;
+ splitter = 1.0;
+ check = 1.0;
+ /* Repeatedly divide `epsilon' by two until it is too small to add to */
+ /* one without causing roundoff. (Also check if the sum is equal to */
+ /* the previous sum, for machines that round up instead of using exact */
+ /* rounding. Not that these routines will work on such machines.) */
+ do {
+ lastcheck = check;
+ epsilon *= half;
+ if (every_other) {
+ splitter *= 2.0;
+ }
+ every_other = !every_other;
+ check = 1.0 + epsilon;
+ } while ((check != 1.0) && (check != lastcheck));
+ splitter += 1.0;
+ /* Error bounds for orientation and incircle tests. */
+ resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
+ ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon;
+ ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon;
+ ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
+ iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
+ iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
+ iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon;
+ o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
+ o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
+ o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
+}
+
+/*****************************************************************************/
+/* */
+/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */
+/* components from the output expansion. */
+/* */
+/* Sets h = e + f. See my Robust Predicates paper for details. */
+/* */
+/* If round-to-even is used (as with IEEE 754), maintains the strongly */
+/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */
+/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */
+/* properties. */
+/* */
+/*****************************************************************************/
+
+int fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h) {
+ REAL Q;
+ REAL Qnew;
+ REAL hh;
+ REAL bvirt;
+ REAL avirt, bround, around;
+ int eindex, findex, hindex;
+ REAL enow, fnow;
+
+ enow = e[0];
+ fnow = f[0];
+ eindex = findex = 0;
+ if ((fnow > enow) == (fnow > -enow)) {
+ Q = enow;
+ enow = e[++eindex];
+ }
+ else {
+ Q = fnow;
+ fnow = f[++findex];
+ }
+ hindex = 0;
+ if ((eindex < elen) && (findex < flen)) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ Fast_Two_Sum(enow, Q, Qnew, hh);
+ enow = e[++eindex];
+ }
+ else {
+ Fast_Two_Sum(fnow, Q, Qnew, hh);
+ fnow = f[++findex];
+ }
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ while ((eindex < elen) && (findex < flen)) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ Two_Sum(Q, enow, Qnew, hh);
+ enow = e[++eindex];
+ }
+ else {
+ Two_Sum(Q, fnow, Qnew, hh);
+ fnow = f[++findex];
+ }
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ }
+ while (eindex < elen) {
+ Two_Sum(Q, enow, Qnew, hh);
+ enow = e[++eindex];
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ while (findex < flen) {
+ Two_Sum(Q, fnow, Qnew, hh);
+ fnow = f[++findex];
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ if ((Q != 0.0) || (hindex == 0)) {
+ h[hindex++] = Q;
+ }
+ return hindex;
+}
+
+/*****************************************************************************/
+/* */
+/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */
+/* eliminating zero components from the */
+/* output expansion. */
+/* */
+/* Sets h = be. See my Robust Predicates paper for details. */
+/* */
+/* Maintains the nonoverlapping property. If round-to-even is used (as */
+/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */
+/* properties as well. (That is, if e has one of these properties, so */
+/* will h.) */
+/* */
+/*****************************************************************************/
+
+int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) {
+ REAL Q, sum;
+ REAL hh;
+ REAL product1;
+ REAL product0;
+ int eindex, hindex;
+ REAL enow;
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+
+ Split(b, bhi, blo);
+ Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
+ hindex = 0;
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ for (eindex = 1; eindex < elen; eindex++) {
+ enow = e[eindex];
+ Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
+ Two_Sum(Q, product0, sum, hh);
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ Fast_Two_Sum(product1, sum, Q, hh);
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ }
+ if ((Q != 0.0) || (hindex == 0)) {
+ h[hindex++] = Q;
+ }
+ return hindex;
+}
+
+/*****************************************************************************/
+/* */
+/* estimate() Produce a one-word estimate of an expansion's value. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL estimate(int elen, REAL *e) {
+ REAL Q;
+ int eindex;
+
+ Q = e[0];
+ for (eindex = 1; eindex < elen; eindex++) {
+ Q += e[eindex];
+ }
+ return Q;
+}
+
+/*****************************************************************************/
+/* */
+/* counterclockwise() Return a positive value if the points pa, pb, and */
+/* pc occur in counterclockwise order; a negative */
+/* value if they occur in clockwise order; and zero */
+/* if they are collinear. The result is also a rough */
+/* approximation of twice the signed area of the */
+/* triangle defined by the three points. */
+/* */
+/* Uses exact arithmetic if necessary to ensure a correct answer. The */
+/* result returned is the determinant of a matrix. This determinant is */
+/* computed adaptively, in the sense that exact arithmetic is used only to */
+/* the degree it is needed to ensure that the returned value has the */
+/* correct sign. Hence, this function is usually quite fast, but will run */
+/* more slowly when the input points are collinear or nearly so. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL counterclockwiseadapt(vertex pa, vertex pb, vertex pc, REAL detsum) {
+ REAL acx, acy, bcx, bcy;
+ REAL acxtail, acytail, bcxtail, bcytail;
+ REAL detleft, detright;
+ REAL detlefttail, detrighttail;
+ REAL det, errbound;
+ REAL B[4], C1[8], C2[12], D[16];
+ REAL B3;
+ int C1length, C2length, Dlength;
+ REAL u[4];
+ REAL u3;
+ REAL s1, t1;
+ REAL s0, t0;
+
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+ REAL _i, _j;
+ REAL _0;
+
+ acx = (REAL) (pa[0] - pc[0]);
+ bcx = (REAL) (pb[0] - pc[0]);
+ acy = (REAL) (pa[1] - pc[1]);
+ bcy = (REAL) (pb[1] - pc[1]);
+
+ Two_Product(acx, bcy, detleft, detlefttail);
+ Two_Product(acy, bcx, detright, detrighttail);
+
+ Two_Two_Diff(detleft, detlefttail, detright, detrighttail, B3, B[2], B[1], B[0]);
+ B[3] = B3;
+
+ det = estimate(4, B);
+ errbound = ccwerrboundB * detsum;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pc[0], acx, acxtail);
+ Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail);
+ Two_Diff_Tail(pa[1], pc[1], acy, acytail);
+ Two_Diff_Tail(pb[1], pc[1], bcy, bcytail);
+
+ if ((acxtail == 0.0) && (acytail == 0.0) && (bcxtail == 0.0) && (bcytail == 0.0)) {
+ return det;
+ }
+
+ errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det);
+ det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Product(acxtail, bcy, s1, s0);
+ Two_Product(acytail, bcx, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1);
+
+ Two_Product(acx, bcytail, s1, s0);
+ Two_Product(acy, bcxtail, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2);
+
+ Two_Product(acxtail, bcytail, s1, s0);
+ Two_Product(acytail, bcxtail, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D);
+
+ return (D[Dlength - 1]);
+}
+
+REAL counterclockwise(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc) {
+ REAL detleft, detright, det;
+ REAL detsum, errbound;
+
+ m->counterclockcount++;
+
+ detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]);
+ detright = (pa[1] - pc[1]) * (pb[0] - pc[0]);
+ det = detleft - detright;
+
+ if (b->noexact) {
+ return det;
+ }
+
+ if (detleft > 0.0) {
+ if (detright <= 0.0) {
+ return det;
+ }
+ else {
+ detsum = detleft + detright;
+ }
+ }
+ else if (detleft < 0.0) {
+ if (detright >= 0.0) {
+ return det;
+ }
+ else {
+ detsum = -detleft - detright;
+ }
+ }
+ else {
+ return det;
+ }
+
+ errbound = ccwerrboundA * detsum;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ return counterclockwiseadapt(pa, pb, pc, detsum);
+}
+
+/*****************************************************************************/
+/* */
+/* incircle() Return a positive value if the point pd lies inside the */
+/* circle passing through pa, pb, and pc; a negative value if */
+/* it lies outside; and zero if the four points are cocircular.*/
+/* The points pa, pb, and pc must be in counterclockwise */
+/* order, or the sign of the result will be reversed. */
+/* */
+/* Uses exact arithmetic if necessary to ensure a correct answer. The */
+/* result returned is the determinant of a matrix. This determinant is */
+/* computed adaptively, in the sense that exact arithmetic is used only to */
+/* the degree it is needed to ensure that the returned value has the */
+/* correct sign. Hence, this function is usually quite fast, but will run */
+/* more slowly when the input points are cocircular or nearly so. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL incircleadapt(vertex pa, vertex pb, vertex pc, vertex pd, REAL permanent) {
+ REAL adx, bdx, cdx, ady, bdy, cdy;
+ REAL det, errbound;
+
+ REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+ REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+ REAL bc[4], ca[4], ab[4];
+ REAL bc3, ca3, ab3;
+ REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32];
+ int axbclen, axxbclen, aybclen, ayybclen, alen;
+ REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32];
+ int bxcalen, bxxcalen, bycalen, byycalen, blen;
+ REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32];
+ int cxablen, cxxablen, cyablen, cyyablen, clen;
+ REAL abdet[64];
+ int ablen;
+ REAL fin1[1152], fin2[1152];
+ REAL *finnow, *finother, *finswap;
+ int finlength;
+
+ REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail;
+ REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1;
+ REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0;
+ REAL aa[4], bb[4], cc[4];
+ REAL aa3, bb3, cc3;
+ REAL ti1, tj1;
+ REAL ti0, tj0;
+ REAL u[4], v[4];
+ REAL u3, v3;
+ REAL temp8[8], temp16a[16], temp16b[16], temp16c[16];
+ REAL temp32a[32], temp32b[32], temp48[48], temp64[64];
+ int temp8len, temp16alen, temp16blen, temp16clen;
+ int temp32alen, temp32blen, temp48len, temp64len;
+ REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8];
+ int axtbblen, axtcclen, aytbblen, aytcclen;
+ REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8];
+ int bxtaalen, bxtcclen, bytaalen, bytcclen;
+ REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8];
+ int cxtaalen, cxtbblen, cytaalen, cytbblen;
+ REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8];
+ int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen;
+ REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16];
+ int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen;
+ REAL axtbctt[8], aytbctt[8], bxtcatt[8];
+ REAL bytcatt[8], cxtabtt[8], cytabtt[8];
+ int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen;
+ REAL abt[8], bct[8], cat[8];
+ int abtlen, bctlen, catlen;
+ REAL abtt[4], bctt[4], catt[4];
+ int abttlen, bcttlen, cattlen;
+ REAL abtt3, bctt3, catt3;
+ REAL negate;
+
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+ REAL _i, _j;
+ REAL _0;
+
+ adx = (REAL) (pa[0] - pd[0]);
+ bdx = (REAL) (pb[0] - pd[0]);
+ cdx = (REAL) (pc[0] - pd[0]);
+ ady = (REAL) (pa[1] - pd[1]);
+ bdy = (REAL) (pb[1] - pd[1]);
+ cdy = (REAL) (pc[1] - pd[1]);
+
+ Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
+ Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
+ Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
+ bc[3] = bc3;
+ axbclen = scale_expansion_zeroelim(4, bc, adx, axbc);
+ axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc);
+ aybclen = scale_expansion_zeroelim(4, bc, ady, aybc);
+ ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc);
+ alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet);
+
+ Two_Product(cdx, ady, cdxady1, cdxady0);
+ Two_Product(adx, cdy, adxcdy1, adxcdy0);
+ Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
+ ca[3] = ca3;
+ bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca);
+ bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca);
+ bycalen = scale_expansion_zeroelim(4, ca, bdy, byca);
+ byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca);
+ blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet);
+
+ Two_Product(adx, bdy, adxbdy1, adxbdy0);
+ Two_Product(bdx, ady, bdxady1, bdxady0);
+ Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
+ ab[3] = ab3;
+ cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab);
+ cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab);
+ cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab);
+ cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab);
+ clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet);
+
+ ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+ finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
+
+ det = estimate(finlength, fin1);
+ errbound = iccerrboundB * permanent;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
+ Two_Diff_Tail(pa[1], pd[1], ady, adytail);
+ Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
+ Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
+ Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
+ Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
+ if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0)
+ && (bdytail == 0.0) && (cdytail == 0.0)) {
+ return det;
+ }
+
+ errbound = iccerrboundC * permanent + resulterrbound * Absolute(det);
+ det += ((adx * adx + ady * ady)
+ * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail))
+ + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx))
+ + ((bdx * bdx + bdy * bdy)
+ * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail))
+ + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx))
+ + ((cdx * cdx + cdy * cdy)
+ * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail))
+ + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx));
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ finnow = fin1;
+ finother = fin2;
+
+ if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) {
+ Square(adx, adxadx1, adxadx0);
+ Square(ady, adyady1, adyady0);
+ Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]);
+ aa[3] = aa3;
+ }
+ if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) {
+ Square(bdx, bdxbdx1, bdxbdx0);
+ Square(bdy, bdybdy1, bdybdy0);
+ Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]);
+ bb[3] = bb3;
+ }
+ if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) {
+ Square(cdx, cdxcdx1, cdxcdx0);
+ Square(cdy, cdycdy1, cdycdy0);
+ Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]);
+ cc[3] = cc3;
+ }
+
+ if (adxtail != 0.0) {
+ axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc);
+ temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, temp16a);
+
+ axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc);
+ temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b);
+
+ axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb);
+ temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc);
+ temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, temp16a);
+
+ aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb);
+ temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b);
+
+ aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc);
+ temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdxtail != 0.0) {
+ bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca);
+ temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, temp16a);
+
+ bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa);
+ temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b);
+
+ bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc);
+ temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca);
+ temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, temp16a);
+
+ bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc);
+ temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b);
+
+ bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa);
+ temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdxtail != 0.0) {
+ cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab);
+ temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, temp16a);
+
+ cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb);
+ temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b);
+
+ cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa);
+ temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab);
+ temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, temp16a);
+
+ cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa);
+ temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b);
+
+ cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb);
+ temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ if ((adxtail != 0.0) || (adytail != 0.0)) {
+ if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) {
+ Two_Product(bdxtail, cdy, ti1, ti0);
+ Two_Product(bdx, cdytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -bdy;
+ Two_Product(cdxtail, negate, ti1, ti0);
+ negate = -bdytail;
+ Two_Product(cdx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct);
+
+ Two_Product(bdxtail, cdytail, ti1, ti0);
+ Two_Product(cdxtail, bdytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]);
+ bctt[3] = bctt3;
+ bcttlen = 4;
+ }
+ else {
+ bct[0] = 0.0;
+ bctlen = 1;
+ bctt[0] = 0.0;
+ bcttlen = 1;
+ }
+
+ if (adxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a);
+ axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct);
+ temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (bdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, temp32a);
+ axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt);
+ temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, temp16a);
+ temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a);
+ aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct);
+ temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, temp32a);
+ aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt);
+ temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, temp16a);
+ temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if ((bdxtail != 0.0) || (bdytail != 0.0)) {
+ if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) {
+ Two_Product(cdxtail, ady, ti1, ti0);
+ Two_Product(cdx, adytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -cdy;
+ Two_Product(adxtail, negate, ti1, ti0);
+ negate = -cdytail;
+ Two_Product(adx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat);
+
+ Two_Product(cdxtail, adytail, ti1, ti0);
+ Two_Product(adxtail, cdytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]);
+ catt[3] = catt3;
+ cattlen = 4;
+ }
+ else {
+ cat[0] = 0.0;
+ catlen = 1;
+ catt[0] = 0.0;
+ cattlen = 1;
+ }
+
+ if (bdxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a);
+ bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat);
+ temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (cdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, temp32a);
+ bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt);
+ temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, temp16a);
+ temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a);
+ bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat);
+ temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, temp32a);
+ bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt);
+ temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, temp16a);
+ temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if ((cdxtail != 0.0) || (cdytail != 0.0)) {
+ if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) {
+ Two_Product(adxtail, bdy, ti1, ti0);
+ Two_Product(adx, bdytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -ady;
+ Two_Product(bdxtail, negate, ti1, ti0);
+ negate = -adytail;
+ Two_Product(bdx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt);
+
+ Two_Product(adxtail, bdytail, ti1, ti0);
+ Two_Product(bdxtail, adytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]);
+ abtt[3] = abtt3;
+ abttlen = 4;
+ }
+ else {
+ abt[0] = 0.0;
+ abtlen = 1;
+ abtt[0] = 0.0;
+ abttlen = 1;
+ }
+
+ if (cdxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a);
+ cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt);
+ temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (adytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, temp32a);
+ cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt);
+ temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, temp16a);
+ temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a);
+ cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt);
+ temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, temp32a);
+ cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt);
+ temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, temp16a);
+ temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+
+ return finnow[finlength - 1];
+}
+
+REAL incircle(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc, vertex pd) {
+ REAL adx, bdx, cdx, ady, bdy, cdy;
+ REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+ REAL alift, blift, clift;
+ REAL det;
+ REAL permanent, errbound;
+
+ m->incirclecount++;
+
+ adx = pa[0] - pd[0];
+ bdx = pb[0] - pd[0];
+ cdx = pc[0] - pd[0];
+ ady = pa[1] - pd[1];
+ bdy = pb[1] - pd[1];
+ cdy = pc[1] - pd[1];
+
+ bdxcdy = bdx * cdy;
+ cdxbdy = cdx * bdy;
+ alift = adx * adx + ady * ady;
+
+ cdxady = cdx * ady;
+ adxcdy = adx * cdy;
+ blift = bdx * bdx + bdy * bdy;
+
+ adxbdy = adx * bdy;
+ bdxady = bdx * ady;
+ clift = cdx * cdx + cdy * cdy;
+
+ det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady);
+
+ if (b->noexact) {
+ return det;
+ }
+
+ permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift
+ + (Absolute(cdxady) + Absolute(adxcdy)) * blift
+ + (Absolute(adxbdy) + Absolute(bdxady)) * clift;
+ errbound = iccerrboundA * permanent;
+ if ((det > errbound) || (-det > errbound)) {
+ return det;
+ }
+
+ return incircleadapt(pa, pb, pc, pd, permanent);
+}
+
+/*****************************************************************************/
+/* */
+/* orient3d() Return a positive value if the point pd lies below the */
+/* plane passing through pa, pb, and pc; "below" is defined so */
+/* that pa, pb, and pc appear in counterclockwise order when */
+/* viewed from above the plane. Returns a negative value if */
+/* pd lies above the plane. Returns zero if the points are */
+/* coplanar. The result is also a rough approximation of six */
+/* times the signed volume of the tetrahedron defined by the */
+/* four points. */
+/* */
+/* Uses exact arithmetic if necessary to ensure a correct answer. The */
+/* result returned is the determinant of a matrix. This determinant is */
+/* computed adaptively, in the sense that exact arithmetic is used only to */
+/* the degree it is needed to ensure that the returned value has the */
+/* correct sign. Hence, this function is usually quite fast, but will run */
+/* more slowly when the input points are coplanar or nearly so. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL orient3dadapt(vertex pa, vertex pb, vertex pc, vertex pd, REAL aheight, REAL bheight,
+ REAL cheight, REAL dheight, REAL permanent) {
+ REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight;
+ REAL det, errbound;
+
+ REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+ REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+ REAL bc[4], ca[4], ab[4];
+ REAL bc3, ca3, ab3;
+ REAL adet[8], bdet[8], cdet[8];
+ int alen, blen, clen;
+ REAL abdet[16];
+ int ablen;
+ REAL *finnow, *finother, *finswap;
+ REAL fin1[192], fin2[192];
+ int finlength;
+
+ REAL adxtail, bdxtail, cdxtail;
+ REAL adytail, bdytail, cdytail;
+ REAL adheighttail, bdheighttail, cdheighttail;
+ REAL at_blarge, at_clarge;
+ REAL bt_clarge, bt_alarge;
+ REAL ct_alarge, ct_blarge;
+ REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
+ int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen;
+ REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1;
+ REAL adxt_cdy1, adxt_bdy1, bdxt_ady1;
+ REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0;
+ REAL adxt_cdy0, adxt_bdy0, bdxt_ady0;
+ REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1;
+ REAL adyt_cdx1, adyt_bdx1, bdyt_adx1;
+ REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0;
+ REAL adyt_cdx0, adyt_bdx0, bdyt_adx0;
+ REAL bct[8], cat[8], abt[8];
+ int bctlen, catlen, abtlen;
+ REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1;
+ REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1;
+ REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0;
+ REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0;
+ REAL u[4], v[12], w[16];
+ REAL u3;
+ int vlength, wlength;
+ REAL negate;
+
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+ REAL _i, _j, _k;
+ REAL _0;
+
+ adx = (REAL) (pa[0] - pd[0]);
+ bdx = (REAL) (pb[0] - pd[0]);
+ cdx = (REAL) (pc[0] - pd[0]);
+ ady = (REAL) (pa[1] - pd[1]);
+ bdy = (REAL) (pb[1] - pd[1]);
+ cdy = (REAL) (pc[1] - pd[1]);
+ adheight = (REAL) (aheight - dheight);
+ bdheight = (REAL) (bheight - dheight);
+ cdheight = (REAL) (cheight - dheight);
+
+ Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
+ Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
+ Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
+ bc[3] = bc3;
+ alen = scale_expansion_zeroelim(4, bc, adheight, adet);
+
+ Two_Product(cdx, ady, cdxady1, cdxady0);
+ Two_Product(adx, cdy, adxcdy1, adxcdy0);
+ Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
+ ca[3] = ca3;
+ blen = scale_expansion_zeroelim(4, ca, bdheight, bdet);
+
+ Two_Product(adx, bdy, adxbdy1, adxbdy0);
+ Two_Product(bdx, ady, bdxady1, bdxady0);
+ Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
+ ab[3] = ab3;
+ clen = scale_expansion_zeroelim(4, ab, cdheight, cdet);
+
+ ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+ finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
+
+ det = estimate(finlength, fin1);
+ errbound = o3derrboundB * permanent;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
+ Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
+ Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
+ Two_Diff_Tail(pa[1], pd[1], ady, adytail);
+ Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
+ Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
+ Two_Diff_Tail(aheight, dheight, adheight, adheighttail);
+ Two_Diff_Tail(bheight, dheight, bdheight, bdheighttail);
+ Two_Diff_Tail(cheight, dheight, cdheight, cdheighttail);
+
+ if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0)
+ && (bdytail == 0.0) && (cdytail == 0.0) && (adheighttail == 0.0) && (bdheighttail == 0.0)
+ && (cdheighttail == 0.0)) {
+ return det;
+ }
+
+ errbound = o3derrboundC * permanent + resulterrbound * Absolute(det);
+ det += (adheight * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail))
+ + adheighttail * (bdx * cdy - bdy * cdx))
+ + (bdheight * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail))
+ + bdheighttail * (cdx * ady - cdy * adx))
+ + (cdheight * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail))
+ + cdheighttail * (adx * bdy - ady * bdx));
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ finnow = fin1;
+ finother = fin2;
+
+ if (adxtail == 0.0) {
+ if (adytail == 0.0) {
+ at_b[0] = 0.0;
+ at_blen = 1;
+ at_c[0] = 0.0;
+ at_clen = 1;
+ }
+ else {
+ negate = -adytail;
+ Two_Product(negate, bdx, at_blarge, at_b[0]);
+ at_b[1] = at_blarge;
+ at_blen = 2;
+ Two_Product(adytail, cdx, at_clarge, at_c[0]);
+ at_c[1] = at_clarge;
+ at_clen = 2;
+ }
+ }
+ else {
+ if (adytail == 0.0) {
+ Two_Product(adxtail, bdy, at_blarge, at_b[0]);
+ at_b[1] = at_blarge;
+ at_blen = 2;
+ negate = -adxtail;
+ Two_Product(negate, cdy, at_clarge, at_c[0]);
+ at_c[1] = at_clarge;
+ at_clen = 2;
+ }
+ else {
+ Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0);
+ Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0);
+ Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, at_blarge, at_b[2], at_b[1],
+ at_b[0]);
+ at_b[3] = at_blarge;
+ at_blen = 4;
+ Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0);
+ Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0);
+ Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, at_clarge, at_c[2], at_c[1],
+ at_c[0]);
+ at_c[3] = at_clarge;
+ at_clen = 4;
+ }
+ }
+ if (bdxtail == 0.0) {
+ if (bdytail == 0.0) {
+ bt_c[0] = 0.0;
+ bt_clen = 1;
+ bt_a[0] = 0.0;
+ bt_alen = 1;
+ }
+ else {
+ negate = -bdytail;
+ Two_Product(negate, cdx, bt_clarge, bt_c[0]);
+ bt_c[1] = bt_clarge;
+ bt_clen = 2;
+ Two_Product(bdytail, adx, bt_alarge, bt_a[0]);
+ bt_a[1] = bt_alarge;
+ bt_alen = 2;
+ }
+ }
+ else {
+ if (bdytail == 0.0) {
+ Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]);
+ bt_c[1] = bt_clarge;
+ bt_clen = 2;
+ negate = -bdxtail;
+ Two_Product(negate, ady, bt_alarge, bt_a[0]);
+ bt_a[1] = bt_alarge;
+ bt_alen = 2;
+ }
+ else {
+ Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0);
+ Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0);
+ Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, bt_clarge, bt_c[2], bt_c[1],
+ bt_c[0]);
+ bt_c[3] = bt_clarge;
+ bt_clen = 4;
+ Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0);
+ Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0);
+ Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, bt_alarge, bt_a[2], bt_a[1],
+ bt_a[0]);
+ bt_a[3] = bt_alarge;
+ bt_alen = 4;
+ }
+ }
+ if (cdxtail == 0.0) {
+ if (cdytail == 0.0) {
+ ct_a[0] = 0.0;
+ ct_alen = 1;
+ ct_b[0] = 0.0;
+ ct_blen = 1;
+ }
+ else {
+ negate = -cdytail;
+ Two_Product(negate, adx, ct_alarge, ct_a[0]);
+ ct_a[1] = ct_alarge;
+ ct_alen = 2;
+ Two_Product(cdytail, bdx, ct_blarge, ct_b[0]);
+ ct_b[1] = ct_blarge;
+ ct_blen = 2;
+ }
+ }
+ else {
+ if (cdytail == 0.0) {
+ Two_Product(cdxtail, ady, ct_alarge, ct_a[0]);
+ ct_a[1] = ct_alarge;
+ ct_alen = 2;
+ negate = -cdxtail;
+ Two_Product(negate, bdy, ct_blarge, ct_b[0]);
+ ct_b[1] = ct_blarge;
+ ct_blen = 2;
+ }
+ else {
+ Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0);
+ Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0);
+ Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, ct_alarge, ct_a[2], ct_a[1],
+ ct_a[0]);
+ ct_a[3] = ct_alarge;
+ ct_alen = 4;
+ Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0);
+ Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0);
+ Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, ct_blarge, ct_b[2], ct_b[1],
+ ct_b[0]);
+ ct_b[3] = ct_blarge;
+ ct_blen = 4;
+ }
+ }
+
+ bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct);
+ wlength = scale_expansion_zeroelim(bctlen, bct, adheight, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat);
+ wlength = scale_expansion_zeroelim(catlen, cat, bdheight, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt);
+ wlength = scale_expansion_zeroelim(abtlen, abt, cdheight, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ if (adheighttail != 0.0) {
+ vlength = scale_expansion_zeroelim(4, bc, adheighttail, v);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdheighttail != 0.0) {
+ vlength = scale_expansion_zeroelim(4, ca, bdheighttail, v);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdheighttail != 0.0) {
+ vlength = scale_expansion_zeroelim(4, ab, cdheighttail, v);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ if (adxtail != 0.0) {
+ if (bdytail != 0.0) {
+ Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0);
+ Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (cdheighttail != 0.0) {
+ Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if (cdytail != 0.0) {
+ negate = -adxtail;
+ Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0);
+ Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (bdheighttail != 0.0) {
+ Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ }
+ if (bdxtail != 0.0) {
+ if (cdytail != 0.0) {
+ Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0);
+ Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (adheighttail != 0.0) {
+ Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if (adytail != 0.0) {
+ negate = -bdxtail;
+ Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0);
+ Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (cdheighttail != 0.0) {
+ Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ }
+ if (cdxtail != 0.0) {
+ if (adytail != 0.0) {
+ Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0);
+ Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (bdheighttail != 0.0) {
+ Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if (bdytail != 0.0) {
+ negate = -cdxtail;
+ Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0);
+ Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (adheighttail != 0.0) {
+ Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ }
+
+ if (adheighttail != 0.0) {
+ wlength = scale_expansion_zeroelim(bctlen, bct, adheighttail, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdheighttail != 0.0) {
+ wlength = scale_expansion_zeroelim(catlen, cat, bdheighttail, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdheighttail != 0.0) {
+ wlength = scale_expansion_zeroelim(abtlen, abt, cdheighttail, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ return finnow[finlength - 1];
+}
+
+REAL orient3d(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc, vertex pd,
+ REAL aheight, REAL bheight, REAL cheight, REAL dheight) {
+ REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight;
+ REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+ REAL det;
+ REAL permanent, errbound;
+
+ m->orient3dcount++;
+
+ adx = pa[0] - pd[0];
+ bdx = pb[0] - pd[0];
+ cdx = pc[0] - pd[0];
+ ady = pa[1] - pd[1];
+ bdy = pb[1] - pd[1];
+ cdy = pc[1] - pd[1];
+ adheight = aheight - dheight;
+ bdheight = bheight - dheight;
+ cdheight = cheight - dheight;
+
+ bdxcdy = bdx * cdy;
+ cdxbdy = cdx * bdy;
+
+ cdxady = cdx * ady;
+ adxcdy = adx * cdy;
+
+ adxbdy = adx * bdy;
+ bdxady = bdx * ady;
+
+ det = adheight * (bdxcdy - cdxbdy) + bdheight * (cdxady - adxcdy) + cdheight * (adxbdy - bdxady);
+
+ if (b->noexact) {
+ return det;
+ }
+
+ permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adheight)
+ + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdheight)
+ + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdheight);
+ errbound = o3derrboundA * permanent;
+ if ((det > errbound) || (-det > errbound)) {
+ return det;
+ }
+
+ return orient3dadapt(pa, pb, pc, pd, aheight, bheight, cheight, dheight, permanent);
+}
+
+/*****************************************************************************/
+/* */
+/* nonregular() Return a positive value if the point pd is incompatible */
+/* with the circle or plane passing through pa, pb, and pc */
+/* (meaning that pd is inside the circle or below the */
+/* plane); a negative value if it is compatible; and zero if */
+/* the four points are cocircular/coplanar. The points pa, */
+/* pb, and pc must be in counterclockwise order, or the sign */
+/* of the result will be reversed. */
+/* */
+/* If the -w switch is used, the points are lifted onto the parabolic */
+/* lifting map, then they are dropped according to their weights, then the */
+/* 3D orientation test is applied. If the -W switch is used, the points' */
+/* heights are already provided, so the 3D orientation test is applied */
+/* directly. If neither switch is used, the incircle test is applied. */
+/* */
+/*****************************************************************************/
+
+REAL nonregular(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc, vertex pd) {
+ if (b->weighted == 0) {
+ return incircle(m, b, pa, pb, pc, pd);
+ }
+ else if (b->weighted == 1) {
+ return orient3d(m, b, pa, pb, pc, pd, pa[0] * pa[0] + pa[1] * pa[1] - pa[2],
+ pb[0] * pb[0] + pb[1] * pb[1] - pb[2], pc[0] * pc[0] + pc[1] * pc[1] - pc[2],
+ pd[0] * pd[0] + pd[1] * pd[1] - pd[2]);
+ }
+ else {
+ return orient3d(m, b, pa, pb, pc, pd, pa[2], pb[2], pc[2], pd[2]);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* findcircumcenter() Find the circumcenter of a triangle. */
+/* */
+/* The result is returned both in terms of x-y coordinates and xi-eta */
+/* (barycentric) coordinates. The xi-eta coordinate system is defined in */
+/* terms of the triangle: the origin of the triangle is the origin of the */
+/* coordinate system; the destination of the triangle is one unit along the */
+/* xi axis; and the apex of the triangle is one unit along the eta axis. */
+/* This procedure also returns the square of the length of the triangle's */
+/* shortest edge. */
+/* */
+/*****************************************************************************/
+
+void findcircumcenter(struct mesh *m, struct behavior *b, vertex torg, vertex tdest, vertex tapex,
+ vertex circumcenter, REAL *xi, REAL *eta, int offcenter) {
+ REAL xdo, ydo, xao, yao;
+ REAL dodist, aodist, dadist;
+ REAL denominator;
+ REAL dx, dy, dxoff, dyoff;
+
+ m->circumcentercount++;
+
+ /* Compute the circumcenter of the triangle. */
+ xdo = tdest[0] - torg[0];
+ ydo = tdest[1] - torg[1];
+ xao = tapex[0] - torg[0];
+ yao = tapex[1] - torg[1];
+ dodist = xdo * xdo + ydo * ydo;
+ aodist = xao * xao + yao * yao;
+ dadist = (tdest[0] - tapex[0]) * (tdest[0] - tapex[0])
+ + (tdest[1] - tapex[1]) * (tdest[1] - tapex[1]);
+ if (b->noexact) {
+ denominator = 0.5 / (xdo * yao - xao * ydo);
+ }
+ else {
+ /* Use the counterclockwise() routine to ensure a positive (and */
+ /* reasonably accurate) result, avoiding any possibility of */
+ /* division by zero. */
+ denominator = 0.5 / counterclockwise(m, b, tdest, tapex, torg);
+ /* Don't count the above as an orientation test. */
+ m->counterclockcount--;
+ }
+ dx = (yao * dodist - ydo * aodist) * denominator;
+ dy = (xdo * aodist - xao * dodist) * denominator;
+
+ /* Find the (squared) length of the triangle's shortest edge. This */
+ /* serves as a conservative estimate of the insertion radius of the */
+ /* circumcenter's parent. The estimate is used to ensure that */
+ /* the algorithm terminates even if very small angles appear in */
+ /* the input PSLG. */
+ if ((dodist < aodist) && (dodist < dadist)) {
+ if (offcenter && (b->offconstant > 0.0)) {
+ /* Find the position of the off-center, as described by Alper Ungor. */
+ dxoff = 0.5 * xdo - b->offconstant * ydo;
+ dyoff = 0.5 * ydo + b->offconstant * xdo;
+ /* If the off-center is closer to the origin than the */
+ /* circumcenter, use the off-center instead. */
+ if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) {
+ dx = dxoff;
+ dy = dyoff;
+ }
+ }
+ }
+ else if (aodist < dadist) {
+ if (offcenter && (b->offconstant > 0.0)) {
+ dxoff = 0.5 * xao + b->offconstant * yao;
+ dyoff = 0.5 * yao - b->offconstant * xao;
+ /* If the off-center is closer to the origin than the */
+ /* circumcenter, use the off-center instead. */
+ if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) {
+ dx = dxoff;
+ dy = dyoff;
+ }
+ }
+ }
+ else {
+ if (offcenter && (b->offconstant > 0.0)) {
+ dxoff = 0.5 * (tapex[0] - tdest[0]) - b->offconstant * (tapex[1] - tdest[1]);
+ dyoff = 0.5 * (tapex[1] - tdest[1]) + b->offconstant * (tapex[0] - tdest[0]);
+ /* If the off-center is closer to the destination than the */
+ /* circumcenter, use the off-center instead. */
+ if (dxoff * dxoff + dyoff * dyoff < (dx - xdo) * (dx - xdo) + (dy - ydo) * (dy - ydo)) {
+ dx = xdo + dxoff;
+ dy = ydo + dyoff;
+ }
+ }
+ }
+
+ circumcenter[0] = torg[0] + dx;
+ circumcenter[1] = torg[1] + dy;
+
+ /* To interpolate vertex attributes for the new vertex inserted at */
+ /* the circumcenter, define a coordinate system with a xi-axis, */
+ /* directed from the triangle's origin to its destination, and */
+ /* an eta-axis, directed from its origin to its apex. */
+ /* Calculate the xi and eta coordinates of the circumcenter. */
+ *xi = (yao * dx - xao * dy) * (2.0 * denominator);
+ *eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
+}
+
+/** **/
+/** **/
+/********* Geometric primitives end here *********/
+
+/*****************************************************************************/
+/* */
+/* triangleinit() Initialize some variables. */
+/* */
+/*****************************************************************************/
+
+void triangleinit(struct mesh *m) {
+ poolzero(&m->vertices);
+ poolzero(&m->triangles);
+ poolzero(&m->subsegs);
+ poolzero(&m->viri);
+ poolzero(&m->badsubsegs);
+ poolzero(&m->badtriangles);
+ poolzero(&m->flipstackers);
+ poolzero(&m->splaynodes);
+
+ m->recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */
+ m->undeads = 0; /* No eliminated input vertices yet. */
+ m->samples = 1; /* Point location should take at least one sample. */
+ m->checksegments = 0; /* There are no segments in the triangulation yet. */
+ m->checkquality = 0; /* The quality triangulation stage has not begun. */
+ m->incirclecount = m->counterclockcount = m->orient3dcount = 0;
+ m->hyperbolacount = m->circletopcount = m->circumcentercount = 0;
+ randomseed = 1;
+
+ exactinit(); /* Initialize exact arithmetic constants. */
+}
+
+/*****************************************************************************/
+/* */
+/* randomnation() Generate a random number between 0 and `choices' - 1. */
+/* */
+/* This is a simple linear congruential random number generator. Hence, it */
+/* is a bad random number generator, but good enough for most randomized */
+/* geometric algorithms. */
+/* */
+/*****************************************************************************/
+
+unsigned long randomnation(unsigned int choices) {
+ randomseed = (randomseed * 1366l + 150889l) % 714025l;
+ return randomseed / (714025l / choices + 1);
+}
+
+/********* Point location routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* makevertexmap() Construct a mapping from vertices to triangles to */
+/* improve the speed of point location for segment */
+/* insertion. */
+/* */
+/* Traverses all the triangles, and provides each corner of each triangle */
+/* with a pointer to that triangle. Of course, pointers will be */
+/* overwritten by other pointers because (almost) each vertex is a corner */
+/* of several triangles, but in the end every vertex will point to some */
+/* triangle that contains it. */
+/* */
+/*****************************************************************************/
+
+void makevertexmap(struct mesh *m, struct behavior *b) {
+ struct otri triangleloop;
+ vertex triorg;
+
+ if (b->verbose) {
+ printf(" Constructing mapping from vertices to triangles.\n");
+ }
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ while (triangleloop.tri != (triangle *) NULL) {
+ /* Check all three vertices of the triangle. */
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ org(triangleloop, triorg);
+ setvertex2tri(triorg, encode(triangleloop));
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* preciselocate() Find a triangle or edge containing a given point. */
+/* */
+/* Begins its search from `searchtri'. It is important that `searchtri' */
+/* be a handle with the property that `searchpoint' is strictly to the left */
+/* of the edge denoted by `searchtri', or is collinear with that edge and */
+/* does not intersect that edge. (In particular, `searchpoint' should not */
+/* be the origin or destination of that edge.) */
+/* */
+/* These conditions are imposed because preciselocate() is normally used in */
+/* one of two situations: */
+/* */
+/* (1) To try to find the location to insert a new point. Normally, we */
+/* know an edge that the point is strictly to the left of. In the */
+/* incremental Delaunay algorithm, that edge is a bounding box edge. */
+/* In Ruppert's Delaunay refinement algorithm for quality meshing, */
+/* that edge is the shortest edge of the triangle whose circumcenter */
+/* is being inserted. */
+/* */
+/* (2) To try to find an existing point. In this case, any edge on the */
+/* convex hull is a good starting edge. You must screen out the */
+/* possibility that the vertex sought is an endpoint of the starting */
+/* edge before you call preciselocate(). */
+/* */
+/* On completion, `searchtri' is a triangle that contains `searchpoint'. */
+/* */
+/* This implementation differs from that given by Guibas and Stolfi. It */
+/* walks from triangle to triangle, crossing an edge only if `searchpoint' */
+/* is on the other side of the line containing that edge. After entering */
+/* a triangle, there are two edges by which one can leave that triangle. */
+/* If both edges are valid (`searchpoint' is on the other side of both */
+/* edges), one of the two is chosen by drawing a line perpendicular to */
+/* the entry edge (whose endpoints are `forg' and `fdest') passing through */
+/* `fapex'. Depending on which side of this perpendicular `searchpoint' */
+/* falls on, an exit edge is chosen. */
+/* */
+/* This implementation is empirically faster than the Guibas and Stolfi */
+/* point location routine (which I originally used), which tends to spiral */
+/* in toward its target. */
+/* */
+/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */
+/* is a handle whose origin is the existing vertex. */
+/* */
+/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */
+/* handle whose primary edge is the edge on which the point lies. */
+/* */
+/* Returns INTRIANGLE if the point lies strictly within a triangle. */
+/* `searchtri' is a handle on the triangle that contains the point. */
+/* */
+/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */
+/* handle whose primary edge the point is to the right of. This might */
+/* occur when the circumcenter of a triangle falls just slightly outside */
+/* the mesh due to floating-point roundoff error. It also occurs when */
+/* seeking a hole or region point that a foolish user has placed outside */
+/* the mesh. */
+/* */
+/* If `stopatsubsegment' is nonzero, the search will stop if it tries to */
+/* walk through a subsegment, and will return OUTSIDE. */
+/* */
+/* WARNING: This routine is designed for convex triangulations, and will */
+/* not generally work after the holes and concavities have been carved. */
+/* However, it can still be used to find the circumcenter of a triangle, as */
+/* long as the search is begun from the triangle in question. */
+/* */
+/*****************************************************************************/
+
+enum locateresult preciselocate(struct mesh *m, struct behavior *b, vertex searchpoint,
+ struct otri *searchtri, int stopatsubsegment) {
+ struct otri backtracktri;
+ struct osub checkedge;
+ vertex forg, fdest, fapex;
+ REAL orgorient, destorient;
+ int moveleft;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose > 2) {
+ printf(" Searching for point (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ }
+ /* Where are we? */
+ org(*searchtri, forg);
+ dest(*searchtri, fdest);
+ apex(*searchtri, fapex);
+ while (1) {
+ if (b->verbose > 2) {
+ printf(
+ " At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]);
+ }
+ /* Check whether the apex is the point we seek. */
+ if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) {
+ lprevself(*searchtri);
+ return ONVERTEX;
+ }
+ /* Does the point lie on the other side of the line defined by the */
+ /* triangle edge opposite the triangle's destination? */
+ destorient = counterclockwise(m, b, forg, fapex, searchpoint);
+ /* Does the point lie on the other side of the line defined by the */
+ /* triangle edge opposite the triangle's origin? */
+ orgorient = counterclockwise(m, b, fapex, fdest, searchpoint);
+ if (destorient > 0.0) {
+ if (orgorient > 0.0) {
+ /* Move left if the inner product of (fapex - searchpoint) and */
+ /* (fdest - forg) is positive. This is equivalent to drawing */
+ /* a line perpendicular to the line (forg, fdest) and passing */
+ /* through `fapex', and determining which side of this line */
+ /* `searchpoint' falls on. */
+ moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0])
+ + (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0;
+ }
+ else {
+ moveleft = 1;
+ }
+ }
+ else {
+ if (orgorient > 0.0) {
+ moveleft = 0;
+ }
+ else {
+ /* The point we seek must be on the boundary of or inside this */
+ /* triangle. */
+ if (destorient == 0.0) {
+ lprevself(*searchtri);
+ return ONEDGE;
+ }
+ if (orgorient == 0.0) {
+ lnextself(*searchtri);
+ return ONEDGE;
+ }
+ return INTRIANGLE;
+ }
+ }
+
+ /* Move to another triangle. Leave a trace `backtracktri' in case */
+ /* floating-point roundoff or some such bogey causes us to walk */
+ /* off a boundary of the triangulation. */
+ if (moveleft) {
+ lprev(*searchtri, backtracktri);
+ fdest = fapex;
+ }
+ else {
+ lnext(*searchtri, backtracktri);
+ forg = fapex;
+ }
+ sym(backtracktri, *searchtri);
+
+ if (m->checksegments && stopatsubsegment) {
+ /* Check for walking through a subsegment. */
+ tspivot(backtracktri, checkedge);
+ if (checkedge.ss != m->dummysub) {
+ /* Go back to the last triangle. */
+ otricopy(backtracktri, *searchtri);
+ return OUTSIDE;
+ }
+ }
+ /* Check for walking right out of the triangulation. */
+ if (searchtri->tri == m->dummytri) {
+ /* Go back to the last triangle. */
+ otricopy(backtracktri, *searchtri);
+ return OUTSIDE;
+ }
+
+ apex(*searchtri, fapex);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* locate() Find a triangle or edge containing a given point. */
+/* */
+/* Searching begins from one of: the input `searchtri', a recently */
+/* encountered triangle `recenttri', or from a triangle chosen from a */
+/* random sample. The choice is made by determining which triangle's */
+/* origin is closest to the point we are searching for. Normally, */
+/* `searchtri' should be a handle on the convex hull of the triangulation. */
+/* */
+/* Details on the random sampling method can be found in the Mucke, Saias, */
+/* and Zhu paper cited in the header of this code. */
+/* */
+/* On completion, `searchtri' is a triangle that contains `searchpoint'. */
+/* */
+/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */
+/* is a handle whose origin is the existing vertex. */
+/* */
+/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */
+/* handle whose primary edge is the edge on which the point lies. */
+/* */
+/* Returns INTRIANGLE if the point lies strictly within a triangle. */
+/* `searchtri' is a handle on the triangle that contains the point. */
+/* */
+/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */
+/* handle whose primary edge the point is to the right of. This might */
+/* occur when the circumcenter of a triangle falls just slightly outside */
+/* the mesh due to floating-point roundoff error. It also occurs when */
+/* seeking a hole or region point that a foolish user has placed outside */
+/* the mesh. */
+/* */
+/* WARNING: This routine is designed for convex triangulations, and will */
+/* not generally work after the holes and concavities have been carved. */
+/* */
+/*****************************************************************************/
+
+enum locateresult locate(struct mesh *m, struct behavior *b, vertex searchpoint,
+ struct otri *searchtri) {
+ VOID **sampleblock;
+ char *firsttri;
+ struct otri sampletri;
+ vertex torg, tdest;
+ unsigned long alignptr;
+ REAL searchdist, dist;
+ REAL ahead;
+ long samplesperblock, totalsamplesleft, samplesleft;
+ long population, totalpopulation;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (b->verbose > 2) {
+ printf(
+ " Randomly sampling for a triangle near point (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ }
+ /* Record the distance from the suggested starting triangle to the */
+ /* point we seek. */
+ org(*searchtri, torg);
+ searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+ + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+ if (b->verbose > 2) {
+ printf(" Boundary triangle has origin (%.12g, %.12g).\n", torg[0], torg[1]);
+ }
+
+ /* If a recently encountered triangle has been recorded and has not been */
+ /* deallocated, test it as a good starting point. */
+ if (m->recenttri.tri != (triangle *) NULL) {
+ if (!deadtri(m->recenttri.tri)) {
+ org(m->recenttri, torg);
+ if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+ otricopy(m->recenttri, *searchtri);
+ return ONVERTEX;
+ }
+ dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+ + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+ if (dist < searchdist) {
+ otricopy(m->recenttri, *searchtri);
+ searchdist = dist;
+ if (b->verbose > 2) {
+ printf(
+ " Choosing recent triangle with origin (%.12g, %.12g).\n", torg[0], torg[1]);
+ }
+ }
+ }
+ }
+
+ /* The number of random samples taken is proportional to the cube root of */
+ /* the number of triangles in the mesh. The next bit of code assumes */
+ /* that the number of triangles increases monotonically (or at least */
+ /* doesn't decrease enough to matter). */
+ while (SAMPLEFACTOR * m->samples * m->samples * m->samples < m->triangles.items) {
+ m->samples++;
+ }
+
+ /* We'll draw ceiling(samples * TRIPERBLOCK / maxitems) random samples */
+ /* from each block of triangles (except the first)--until we meet the */
+ /* sample quota. The ceiling means that blocks at the end might be */
+ /* neglected, but I don't care. */
+ samplesperblock = (m->samples * TRIPERBLOCK - 1) / m->triangles.maxitems + 1;
+ /* We'll draw ceiling(samples * itemsfirstblock / maxitems) random samples */
+ /* from the first block of triangles. */
+ samplesleft = (m->samples * m->triangles.itemsfirstblock - 1) / m->triangles.maxitems + 1;
+ totalsamplesleft = m->samples;
+ population = m->triangles.itemsfirstblock;
+ totalpopulation = m->triangles.maxitems;
+ sampleblock = m->triangles.firstblock;
+ sampletri.orient = 0;
+ while (totalsamplesleft > 0) {
+ /* If we're in the last block, `population' needs to be corrected. */
+ if (population > totalpopulation) {
+ population = totalpopulation;
+ }
+ /* Find a pointer to the first triangle in the block. */
+ alignptr = (unsigned long) (sampleblock + 1);
+ firsttri = (char *) (alignptr + (unsigned long) m->triangles.alignbytes
+ - (alignptr % (unsigned long) m->triangles.alignbytes));
+
+ /* Choose `samplesleft' randomly sampled triangles in this block. */
+ do {
+ sampletri.tri = (triangle *) (firsttri
+ + (randomnation((unsigned int) population) * m->triangles.itembytes));
+ if (!deadtri(sampletri.tri)) {
+ org(sampletri, torg);
+ dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+ + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+ if (dist < searchdist) {
+ otricopy(sampletri, *searchtri);
+ searchdist = dist;
+ if (b->verbose > 2) {
+ printf(" Choosing triangle with origin (%.12g, %.12g).\n", torg[0], torg[1]);
+ }
+ }
+ }
+
+ samplesleft--;
+ totalsamplesleft--;
+ } while ((samplesleft > 0) && (totalsamplesleft > 0));
+
+ if (totalsamplesleft > 0) {
+ sampleblock = (VOID **) *sampleblock;
+ samplesleft = samplesperblock;
+ totalpopulation -= population;
+ population = TRIPERBLOCK;
+ }
+ }
+
+ /* Where are we? */
+ org(*searchtri, torg);
+ dest(*searchtri, tdest);
+ /* Check the starting triangle's vertices. */
+ if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+ return ONVERTEX;
+ }
+ if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) {
+ lnextself(*searchtri);
+ return ONVERTEX;
+ }
+ /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */
+ ahead = counterclockwise(m, b, torg, tdest, searchpoint);
+ if (ahead < 0.0) {
+ /* Turn around so that `searchpoint' is to the left of the */
+ /* edge specified by `searchtri'. */
+ symself(*searchtri);
+ }
+ else if (ahead == 0.0) {
+ /* Check if `searchpoint' is between `torg' and `tdest'. */
+ if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0]))
+ && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) {
+ return ONEDGE;
+ }
+ }
+ return preciselocate(m, b, searchpoint, searchtri, 0);
+}
+
+/** **/
+/** **/
+/********* Point location routines end here *********/
+
+/********* Mesh transformation routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* insertsubseg() Create a new subsegment and insert it between two */
+/* triangles. */
+/* */
+/* The new subsegment is inserted at the edge described by the handle */
+/* `tri'. Its vertices are properly initialized. The marker `subsegmark' */
+/* is applied to the subsegment and, if appropriate, its vertices. */
+/* */
+/*****************************************************************************/
+
+void insertsubseg(struct mesh *m, struct behavior *b, struct otri *tri, int subsegmark) {
+ struct otri oppotri;
+ struct osub newsubseg;
+ vertex triorg, tridest;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ org(*tri, triorg);
+ dest(*tri, tridest);
+ /* Mark vertices if possible. */
+ if (vertexmark(triorg) == 0) {
+ setvertexmark(triorg, subsegmark);
+ }
+ if (vertexmark(tridest) == 0) {
+ setvertexmark(tridest, subsegmark);
+ }
+ /* Check if there's already a subsegment here. */
+ tspivot(*tri, newsubseg);
+ if (newsubseg.ss == m->dummysub) {
+ /* Make new subsegment and initialize its vertices. */
+ makesubseg(m, &newsubseg);
+ setsorg(newsubseg, tridest);
+ setsdest(newsubseg, triorg);
+ setsegorg(newsubseg, tridest);
+ setsegdest(newsubseg, triorg);
+ /* Bond new subsegment to the two triangles it is sandwiched between. */
+ /* Note that the facing triangle `oppotri' might be equal to */
+ /* `dummytri' (outer space), but the new subsegment is bonded to it */
+ /* all the same. */
+ tsbond(*tri, newsubseg);
+ sym(*tri, oppotri);
+ ssymself(newsubseg);
+ tsbond(oppotri, newsubseg);
+ setmark(newsubseg, subsegmark);
+ if (b->verbose > 2) {
+ printf(" Inserting new ");
+ printsubseg(m, b, &newsubseg);
+ }
+ }
+ else {
+ if (mark(newsubseg) == 0) {
+ setmark(newsubseg, subsegmark);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* Terminology */
+/* */
+/* A "local transformation" replaces a small set of triangles with another */
+/* set of triangles. This may or may not involve inserting or deleting a */
+/* vertex. */
+/* */
+/* The term "casing" is used to describe the set of triangles that are */
+/* attached to the triangles being transformed, but are not transformed */
+/* themselves. Think of the casing as a fixed hollow structure inside */
+/* which all the action happens. A "casing" is only defined relative to */
+/* a single transformation; each occurrence of a transformation will */
+/* involve a different casing. */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* */
+/* flip() Transform two triangles to two different triangles by flipping */
+/* an edge counterclockwise within a quadrilateral. */
+/* */
+/* Imagine the original triangles, abc and bad, oriented so that the */
+/* shared edge ab lies in a horizontal plane, with the vertex b on the left */
+/* and the vertex a on the right. The vertex c lies below the edge, and */
+/* the vertex d lies above the edge. The `flipedge' handle holds the edge */
+/* ab of triangle abc, and is directed left, from vertex a to vertex b. */
+/* */
+/* The triangles abc and bad are deleted and replaced by the triangles cdb */
+/* and dca. The triangles that represent abc and bad are NOT deallocated; */
+/* they are reused for dca and cdb, respectively. Hence, any handles that */
+/* may have held the original triangles are still valid, although not */
+/* directed as they were before. */
+/* */
+/* Upon completion of this routine, the `flipedge' handle holds the edge */
+/* dc of triangle dca, and is directed down, from vertex d to vertex c. */
+/* (Hence, the two triangles have rotated counterclockwise.) */
+/* */
+/* WARNING: This transformation is geometrically valid only if the */
+/* quadrilateral adbc is convex. Furthermore, this transformation is */
+/* valid only if there is not a subsegment between the triangles abc and */
+/* bad. This routine does not check either of these preconditions, and */
+/* it is the responsibility of the calling routine to ensure that they are */
+/* met. If they are not, the streets shall be filled with wailing and */
+/* gnashing of teeth. */
+/* */
+/*****************************************************************************/
+
+void flip(struct mesh *m, struct behavior *b, struct otri *flipedge) {
+ struct otri botleft, botright;
+ struct otri topleft, topright;
+ struct otri top;
+ struct otri botlcasing, botrcasing;
+ struct otri toplcasing, toprcasing;
+ struct osub botlsubseg, botrsubseg;
+ struct osub toplsubseg, toprsubseg;
+ vertex leftvertex, rightvertex, botvertex;
+ vertex farvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ /* Identify the vertices of the quadrilateral. */
+ org(*flipedge, rightvertex);
+ dest(*flipedge, leftvertex);
+ apex(*flipedge, botvertex);
+ sym(*flipedge, top);
+#ifdef SELF_CHECK
+ if (top.tri == m->dummytri)
+ {
+ printf("Internal error in flip(): Attempt to flip on boundary.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ if (m->checksegments)
+ {
+ tspivot(*flipedge, toplsubseg);
+ if (toplsubseg.ss != m->dummysub)
+ {
+ printf("Internal error in flip(): Attempt to flip a segment.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ }
+#endif /* SELF_CHECK */
+ apex(top, farvertex);
+
+ /* Identify the casing of the quadrilateral. */
+ lprev(top, topleft);
+ sym(topleft, toplcasing);
+ lnext(top, topright);
+ sym(topright, toprcasing);
+ lnext(*flipedge, botleft);
+ sym(botleft, botlcasing);
+ lprev(*flipedge, botright);
+ sym(botright, botrcasing);
+ /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+ bond(topleft, botlcasing);
+ bond(botleft, botrcasing);
+ bond(botright, toprcasing);
+ bond(topright, toplcasing);
+
+ if (m->checksegments) {
+ /* Check for subsegments and rebond them to the quadrilateral. */
+ tspivot(topleft, toplsubseg);
+ tspivot(botleft, botlsubseg);
+ tspivot(botright, botrsubseg);
+ tspivot(topright, toprsubseg);
+ if (toplsubseg.ss == m->dummysub) {
+ tsdissolve(topright);
+ }
+ else {
+ tsbond(topright, toplsubseg);
+ }
+ if (botlsubseg.ss == m->dummysub) {
+ tsdissolve(topleft);
+ }
+ else {
+ tsbond(topleft, botlsubseg);
+ }
+ if (botrsubseg.ss == m->dummysub) {
+ tsdissolve(botleft);
+ }
+ else {
+ tsbond(botleft, botrsubseg);
+ }
+ if (toprsubseg.ss == m->dummysub) {
+ tsdissolve(botright);
+ }
+ else {
+ tsbond(botright, toprsubseg);
+ }
+ }
+
+ /* New vertex assignments for the rotated quadrilateral. */
+ setorg(*flipedge, farvertex);
+ setdest(*flipedge, botvertex);
+ setapex(*flipedge, rightvertex);
+ setorg(top, botvertex);
+ setdest(top, farvertex);
+ setapex(top, leftvertex);
+ if (b->verbose > 2) {
+ printf(" Edge flip results in left ");
+ printtriangle(m, b, &top);
+ printf(" and right ");
+ printtriangle(m, b, flipedge);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* unflip() Transform two triangles to two different triangles by */
+/* flipping an edge clockwise within a quadrilateral. Reverses */
+/* the flip() operation so that the data structures representing */
+/* the triangles are back where they were before the flip(). */
+/* */
+/* Imagine the original triangles, abc and bad, oriented so that the */
+/* shared edge ab lies in a horizontal plane, with the vertex b on the left */
+/* and the vertex a on the right. The vertex c lies below the edge, and */
+/* the vertex d lies above the edge. The `flipedge' handle holds the edge */
+/* ab of triangle abc, and is directed left, from vertex a to vertex b. */
+/* */
+/* The triangles abc and bad are deleted and replaced by the triangles cdb */
+/* and dca. The triangles that represent abc and bad are NOT deallocated; */
+/* they are reused for cdb and dca, respectively. Hence, any handles that */
+/* may have held the original triangles are still valid, although not */
+/* directed as they were before. */
+/* */
+/* Upon completion of this routine, the `flipedge' handle holds the edge */
+/* cd of triangle cdb, and is directed up, from vertex c to vertex d. */
+/* (Hence, the two triangles have rotated clockwise.) */
+/* */
+/* WARNING: This transformation is geometrically valid only if the */
+/* quadrilateral adbc is convex. Furthermore, this transformation is */
+/* valid only if there is not a subsegment between the triangles abc and */
+/* bad. This routine does not check either of these preconditions, and */
+/* it is the responsibility of the calling routine to ensure that they are */
+/* met. If they are not, the streets shall be filled with wailing and */
+/* gnashing of teeth. */
+/* */
+/*****************************************************************************/
+
+void unflip(struct mesh *m, struct behavior *b, struct otri *flipedge) {
+ struct otri botleft, botright;
+ struct otri topleft, topright;
+ struct otri top;
+ struct otri botlcasing, botrcasing;
+ struct otri toplcasing, toprcasing;
+ struct osub botlsubseg, botrsubseg;
+ struct osub toplsubseg, toprsubseg;
+ vertex leftvertex, rightvertex, botvertex;
+ vertex farvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ /* Identify the vertices of the quadrilateral. */
+ org(*flipedge, rightvertex);
+ dest(*flipedge, leftvertex);
+ apex(*flipedge, botvertex);
+ sym(*flipedge, top);
+#ifdef SELF_CHECK
+ if (top.tri == m->dummytri)
+ {
+ printf("Internal error in unflip(): Attempt to flip on boundary.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ if (m->checksegments)
+ {
+ tspivot(*flipedge, toplsubseg);
+ if (toplsubseg.ss != m->dummysub)
+ {
+ printf("Internal error in unflip(): Attempt to flip a subsegment.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ }
+#endif /* SELF_CHECK */
+ apex(top, farvertex);
+
+ /* Identify the casing of the quadrilateral. */
+ lprev(top, topleft);
+ sym(topleft, toplcasing);
+ lnext(top, topright);
+ sym(topright, toprcasing);
+ lnext(*flipedge, botleft);
+ sym(botleft, botlcasing);
+ lprev(*flipedge, botright);
+ sym(botright, botrcasing);
+ /* Rotate the quadrilateral one-quarter turn clockwise. */
+ bond(topleft, toprcasing);
+ bond(botleft, toplcasing);
+ bond(botright, botlcasing);
+ bond(topright, botrcasing);
+
+ if (m->checksegments) {
+ /* Check for subsegments and rebond them to the quadrilateral. */
+ tspivot(topleft, toplsubseg);
+ tspivot(botleft, botlsubseg);
+ tspivot(botright, botrsubseg);
+ tspivot(topright, toprsubseg);
+ if (toplsubseg.ss == m->dummysub) {
+ tsdissolve(botleft);
+ }
+ else {
+ tsbond(botleft, toplsubseg);
+ }
+ if (botlsubseg.ss == m->dummysub) {
+ tsdissolve(botright);
+ }
+ else {
+ tsbond(botright, botlsubseg);
+ }
+ if (botrsubseg.ss == m->dummysub) {
+ tsdissolve(topright);
+ }
+ else {
+ tsbond(topright, botrsubseg);
+ }
+ if (toprsubseg.ss == m->dummysub) {
+ tsdissolve(topleft);
+ }
+ else {
+ tsbond(topleft, toprsubseg);
+ }
+ }
+
+ /* New vertex assignments for the rotated quadrilateral. */
+ setorg(*flipedge, botvertex);
+ setdest(*flipedge, farvertex);
+ setapex(*flipedge, leftvertex);
+ setorg(top, farvertex);
+ setdest(top, botvertex);
+ setapex(top, rightvertex);
+ if (b->verbose > 2) {
+ printf(" Edge unflip results in left ");
+ printtriangle(m, b, flipedge);
+ printf(" and right ");
+ printtriangle(m, b, &top);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* insertvertex() Insert a vertex into a Delaunay triangulation, */
+/* performing flips as necessary to maintain the Delaunay */
+/* property. */
+/* */
+/* The point `insertvertex' is located. If `searchtri.tri' is not NULL, */
+/* the search for the containing triangle begins from `searchtri'. If */
+/* `searchtri.tri' is NULL, a full point location procedure is called. */
+/* If `insertvertex' is found inside a triangle, the triangle is split into */
+/* three; if `insertvertex' lies on an edge, the edge is split in two, */
+/* thereby splitting the two adjacent triangles into four. Edge flips are */
+/* used to restore the Delaunay property. If `insertvertex' lies on an */
+/* existing vertex, no action is taken, and the value DUPLICATEVERTEX is */
+/* returned. On return, `searchtri' is set to a handle whose origin is the */
+/* existing vertex. */
+/* */
+/* Normally, the parameter `splitseg' is set to NULL, implying that no */
+/* subsegment should be split. In this case, if `insertvertex' is found to */
+/* lie on a segment, no action is taken, and the value VIOLATINGVERTEX is */
+/* returned. On return, `searchtri' is set to a handle whose primary edge */
+/* is the violated subsegment. */
+/* */
+/* If the calling routine wishes to split a subsegment by inserting a */
+/* vertex in it, the parameter `splitseg' should be that subsegment. In */
+/* this case, `searchtri' MUST be the triangle handle reached by pivoting */
+/* from that subsegment; no point location is done. */
+/* */
+/* `segmentflaws' and `triflaws' are flags that indicate whether or not */
+/* there should be checks for the creation of encroached subsegments or bad */
+/* quality triangles. If a newly inserted vertex encroaches upon */
+/* subsegments, these subsegments are added to the list of subsegments to */
+/* be split if `segmentflaws' is set. If bad triangles are created, these */
+/* are added to the queue if `triflaws' is set. */
+/* */
+/* If a duplicate vertex or violated segment does not prevent the vertex */
+/* from being inserted, the return value will be ENCROACHINGVERTEX if the */
+/* vertex encroaches upon a subsegment (and checking is enabled), or */
+/* SUCCESSFULVERTEX otherwise. In either case, `searchtri' is set to a */
+/* handle whose origin is the newly inserted vertex. */
+/* */
+/* insertvertex() does not use flip() for reasons of speed; some */
+/* information can be reused from edge flip to edge flip, like the */
+/* locations of subsegments. */
+/* */
+/*****************************************************************************/
+
+enum insertvertexresult insertvertex(struct mesh *m, struct behavior *b, vertex newvertex,
+ struct otri *searchtri, struct osub *splitseg, int segmentflaws, int triflaws) {
+ struct otri horiz;
+ struct otri top;
+ struct otri botleft, botright;
+ struct otri topleft, topright;
+ struct otri newbotleft, newbotright;
+ struct otri newtopright;
+ struct otri botlcasing, botrcasing;
+ struct otri toplcasing, toprcasing;
+ struct otri testtri;
+ struct osub botlsubseg, botrsubseg;
+ struct osub toplsubseg, toprsubseg;
+ struct osub brokensubseg;
+ struct osub checksubseg;
+ struct osub rightsubseg;
+ struct osub newsubseg;
+ struct badsubseg *encroached;
+ struct flipstacker *newflip;
+ vertex first;
+ vertex leftvertex, rightvertex, botvertex, topvertex, farvertex;
+ vertex segmentorg, segmentdest;
+ REAL attrib;
+ REAL area;
+ enum insertvertexresult success;
+ enum locateresult intersect;
+ int doflip;
+ int mirrorflag;
+ int enq;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by spivot() and tspivot(). */
+
+ if (b->verbose > 1) {
+ printf(" Inserting (%.12g, %.12g).\n", newvertex[0], newvertex[1]);
+ }
+
+ if (splitseg == (struct osub *) NULL) {
+ /* Find the location of the vertex to be inserted. Check if a good */
+ /* starting triangle has already been provided by the caller. */
+ if (searchtri->tri == m->dummytri) {
+ /* Find a boundary triangle. */
+ horiz.tri = m->dummytri;
+ horiz.orient = 0;
+ symself(horiz);
+ /* Search for a triangle containing `newvertex'. */
+ intersect = locate(m, b, newvertex, &horiz);
+ }
+ else {
+ /* Start searching from the triangle provided by the caller. */
+ otricopy(*searchtri, horiz);
+ intersect = preciselocate(m, b, newvertex, &horiz, 1);
+ }
+ }
+ else {
+ /* The calling routine provides the subsegment in which */
+ /* the vertex is inserted. */
+ otricopy(*searchtri, horiz);
+ intersect = ONEDGE;
+ }
+
+ if (intersect == ONVERTEX) {
+ /* There's already a vertex there. Return in `searchtri' a triangle */
+ /* whose origin is the existing vertex. */
+ otricopy(horiz, *searchtri);
+ otricopy(horiz, m->recenttri);
+ return DUPLICATEVERTEX;
+ }
+ if ((intersect == ONEDGE) || (intersect == OUTSIDE)) {
+ /* The vertex falls on an edge or boundary. */
+ if (m->checksegments && (splitseg == (struct osub *) NULL)) {
+ /* Check whether the vertex falls on a subsegment. */
+ tspivot(horiz, brokensubseg);
+ if (brokensubseg.ss != m->dummysub) {
+ /* The vertex falls on a subsegment, and hence will not be inserted. */
+ if (segmentflaws) {
+ enq = b->nobisect != 2;
+ if (enq && (b->nobisect == 1)) {
+ /* This subsegment may be split only if it is an */
+ /* internal boundary. */
+ sym(horiz, testtri);
+ enq = testtri.tri != m->dummytri;
+ }
+ if (enq) {
+ /* Add the subsegment to the list of encroached subsegments. */
+ encroached = (struct badsubseg *) poolalloc(&m->badsubsegs);
+ encroached->encsubseg = sencode(brokensubseg);
+ sorg(brokensubseg, encroached->subsegorg);
+ sdest(brokensubseg, encroached->subsegdest);
+ if (b->verbose > 2) {
+ printf(
+ " Queueing encroached subsegment (%.12g, %.12g) (%.12g, %.12g).\n", encroached->subsegorg[0], encroached->subsegorg[1], encroached->subsegdest[0], encroached->subsegdest[1]);
+ }
+ }
+ }
+ /* Return a handle whose primary edge contains the vertex, */
+ /* which has not been inserted. */
+ otricopy(horiz, *searchtri);
+ otricopy(horiz, m->recenttri);
+ return VIOLATINGVERTEX;
+ }
+ }
+
+ /* Insert the vertex on an edge, dividing one triangle into two (if */
+ /* the edge lies on a boundary) or two triangles into four. */
+ lprev(horiz, botright);
+ sym(botright, botrcasing);
+ sym(horiz, topright);
+ /* Is there a second triangle? (Or does this edge lie on a boundary?) */
+ mirrorflag = topright.tri != m->dummytri;
+ if (mirrorflag) {
+ lnextself(topright);
+ sym(topright, toprcasing);
+ maketriangle(m, b, &newtopright);
+ }
+ else {
+ /* Splitting a boundary edge increases the number of boundary edges. */
+ m->hullsize++;
+ }
+ maketriangle(m, b, &newbotright);
+
+ /* Set the vertices of changed and new triangles. */
+ org(horiz, rightvertex);
+ dest(horiz, leftvertex);
+ apex(horiz, botvertex);
+ setorg(newbotright, botvertex);
+ setdest(newbotright, rightvertex);
+ setapex(newbotright, newvertex);
+ setorg(horiz, newvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Set the element attributes of a new triangle. */
+ setelemattribute(newbotright, i, elemattribute(botright, i));
+ }
+ if (b->vararea) {
+ /* Set the area constraint of a new triangle. */
+ setareabound(newbotright, areabound(botright));
+ }
+ if (mirrorflag) {
+ dest(topright, topvertex);
+ setorg(newtopright, rightvertex);
+ setdest(newtopright, topvertex);
+ setapex(newtopright, newvertex);
+ setorg(topright, newvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Set the element attributes of another new triangle. */
+ setelemattribute(newtopright, i, elemattribute(topright, i));
+ }
+ if (b->vararea) {
+ /* Set the area constraint of another new triangle. */
+ setareabound(newtopright, areabound(topright));
+ }
+ }
+
+ /* There may be subsegments that need to be bonded */
+ /* to the new triangle(s). */
+ if (m->checksegments) {
+ tspivot(botright, botrsubseg);
+ if (botrsubseg.ss != m->dummysub) {
+ tsdissolve(botright);
+ tsbond(newbotright, botrsubseg);
+ }
+ if (mirrorflag) {
+ tspivot(topright, toprsubseg);
+ if (toprsubseg.ss != m->dummysub) {
+ tsdissolve(topright);
+ tsbond(newtopright, toprsubseg);
+ }
+ }
+ }
+
+ /* Bond the new triangle(s) to the surrounding triangles. */
+ bond(newbotright, botrcasing);
+ lprevself(newbotright);
+ bond(newbotright, botright);
+ lprevself(newbotright);
+ if (mirrorflag) {
+ bond(newtopright, toprcasing);
+ lnextself(newtopright);
+ bond(newtopright, topright);
+ lnextself(newtopright);
+ bond(newtopright, newbotright);
+ }
+
+ if (splitseg != (struct osub *) NULL) {
+ /* Split the subsegment into two. */
+ setsdest(*splitseg, newvertex);
+ segorg(*splitseg, segmentorg);
+ segdest(*splitseg, segmentdest);
+ ssymself(*splitseg);
+ spivot(*splitseg, rightsubseg);
+ insertsubseg(m, b, &newbotright, mark(*splitseg));
+ tspivot(newbotright, newsubseg);
+ setsegorg(newsubseg, segmentorg);
+ setsegdest(newsubseg, segmentdest);
+ sbond(*splitseg, newsubseg);
+ ssymself(newsubseg);
+ sbond(newsubseg, rightsubseg);
+ ssymself(*splitseg);
+ /* Transfer the subsegment's boundary marker to the vertex */
+ /* if required. */
+ if (vertexmark(newvertex) == 0) {
+ setvertexmark(newvertex, mark(*splitseg));
+ }
+ }
+
+ if (m->checkquality) {
+ poolrestart(&m->flipstackers);
+ m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+ m->lastflip->flippedtri = encode(horiz);
+ m->lastflip->prevflip = (struct flipstacker *) &insertvertex;
+ }
+
+#ifdef SELF_CHECK
+ if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle prior to edge vertex insertion (bottom).\n");
+ }
+ if (mirrorflag)
+ {
+ if (counterclockwise(m, b, leftvertex, rightvertex, topvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to edge vertex insertion (top).\n");
+ }
+ if (counterclockwise(m, b, rightvertex, topvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (top right).\n");
+ }
+ if (counterclockwise(m, b, topvertex, leftvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (top left).\n");
+ }
+ }
+ if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (bottom left).\n");
+ }
+ if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (bottom right).\n");
+ }
+#endif /* SELF_CHECK */
+ if (b->verbose > 2) {
+ printf(" Updating bottom left ");
+ printtriangle(m, b, &botright);
+ if (mirrorflag) {
+ printf(" Updating top left ");
+ printtriangle(m, b, &topright);
+ printf(" Creating top right ");
+ printtriangle(m, b, &newtopright);
+ }
+ printf(" Creating bottom right ");
+ printtriangle(m, b, &newbotright);
+ }
+
+ /* Position `horiz' on the first edge to check for */
+ /* the Delaunay property. */
+ lnextself(horiz);
+ }
+ else {
+ /* Insert the vertex in a triangle, splitting it into three. */
+ lnext(horiz, botleft);
+ lprev(horiz, botright);
+ sym(botleft, botlcasing);
+ sym(botright, botrcasing);
+ maketriangle(m, b, &newbotleft);
+ maketriangle(m, b, &newbotright);
+
+ /* Set the vertices of changed and new triangles. */
+ org(horiz, rightvertex);
+ dest(horiz, leftvertex);
+ apex(horiz, botvertex);
+ setorg(newbotleft, leftvertex);
+ setdest(newbotleft, botvertex);
+ setapex(newbotleft, newvertex);
+ setorg(newbotright, botvertex);
+ setdest(newbotright, rightvertex);
+ setapex(newbotright, newvertex);
+ setapex(horiz, newvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Set the element attributes of the new triangles. */
+ attrib = elemattribute(horiz, i);
+ setelemattribute(newbotleft, i, attrib);
+ setelemattribute(newbotright, i, attrib);
+ }
+ if (b->vararea) {
+ /* Set the area constraint of the new triangles. */
+ area = areabound(horiz);
+ setareabound(newbotleft, area);
+ setareabound(newbotright, area);
+ }
+
+ /* There may be subsegments that need to be bonded */
+ /* to the new triangles. */
+ if (m->checksegments) {
+ tspivot(botleft, botlsubseg);
+ if (botlsubseg.ss != m->dummysub) {
+ tsdissolve(botleft);
+ tsbond(newbotleft, botlsubseg);
+ }
+ tspivot(botright, botrsubseg);
+ if (botrsubseg.ss != m->dummysub) {
+ tsdissolve(botright);
+ tsbond(newbotright, botrsubseg);
+ }
+ }
+
+ /* Bond the new triangles to the surrounding triangles. */
+ bond(newbotleft, botlcasing);
+ bond(newbotright, botrcasing);
+ lnextself(newbotleft);
+ lprevself(newbotright);
+ bond(newbotleft, newbotright);
+ lnextself(newbotleft);
+ bond(botleft, newbotleft);
+ lprevself(newbotright);
+ bond(botright, newbotright);
+
+ if (m->checkquality) {
+ poolrestart(&m->flipstackers);
+ m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+ m->lastflip->flippedtri = encode(horiz);
+ m->lastflip->prevflip = (struct flipstacker *) NULL;
+ }
+
+#ifdef SELF_CHECK
+ if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to vertex insertion.\n");
+ }
+ if (counterclockwise(m, b, rightvertex, leftvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after vertex insertion (top).\n");
+ }
+ if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after vertex insertion (left).\n");
+ }
+ if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after vertex insertion (right).\n");
+ }
+#endif /* SELF_CHECK */
+ if (b->verbose > 2) {
+ printf(" Updating top ");
+ printtriangle(m, b, &horiz);
+ printf(" Creating left ");
+ printtriangle(m, b, &newbotleft);
+ printf(" Creating right ");
+ printtriangle(m, b, &newbotright);
+ }
+ }
+
+ /* The insertion is successful by default, unless an encroached */
+ /* subsegment is found. */
+ success = SUCCESSFULVERTEX;
+ /* Circle around the newly inserted vertex, checking each edge opposite */
+ /* it for the Delaunay property. Non-Delaunay edges are flipped. */
+ /* `horiz' is always the edge being checked. `first' marks where to */
+ /* stop circling. */
+ org(horiz, first);
+ rightvertex = first;
+ dest(horiz, leftvertex);
+ /* Circle until finished. */
+ while (1) {
+ /* By default, the edge will be flipped. */
+ doflip = 1;
+
+ if (m->checksegments) {
+ /* Check for a subsegment, which cannot be flipped. */
+ tspivot(horiz, checksubseg);
+ if (checksubseg.ss != m->dummysub) {
+ /* The edge is a subsegment and cannot be flipped. */
+ doflip = 0;
+#ifndef CDT_ONLY
+ if (segmentflaws)
+ {
+ /* Does the new vertex encroach upon this subsegment? */
+ if (checkseg4encroach(m, b, &checksubseg))
+ {
+ success = ENCROACHINGVERTEX;
+ }
+ }
+#endif /* not CDT_ONLY */
+ }
+ }
+
+ if (doflip) {
+ /* Check if the edge is a boundary edge. */
+ sym(horiz, top);
+ if (top.tri == m->dummytri) {
+ /* The edge is a boundary edge and cannot be flipped. */
+ doflip = 0;
+ }
+ else {
+ /* Find the vertex on the other side of the edge. */
+ apex(top, farvertex);
+ /* In the incremental Delaunay triangulation algorithm, any of */
+ /* `leftvertex', `rightvertex', and `farvertex' could be vertices */
+ /* of the triangular bounding box. These vertices must be */
+ /* treated as if they are infinitely distant, even though their */
+ /* "coordinates" are not. */
+ if ((leftvertex == m->infvertex1) || (leftvertex == m->infvertex2)
+ || (leftvertex == m->infvertex3)) {
+ /* `leftvertex' is infinitely distant. Check the convexity of */
+ /* the boundary of the triangulation. 'farvertex' might be */
+ /* infinite as well, but trust me, this same condition should */
+ /* be applied. */
+ doflip = counterclockwise(m, b, newvertex, rightvertex, farvertex) > 0.0;
+ }
+ else if ((rightvertex == m->infvertex1) || (rightvertex == m->infvertex2)
+ || (rightvertex == m->infvertex3)) {
+ /* `rightvertex' is infinitely distant. Check the convexity of */
+ /* the boundary of the triangulation. 'farvertex' might be */
+ /* infinite as well, but trust me, this same condition should */
+ /* be applied. */
+ doflip = counterclockwise(m, b, farvertex, leftvertex, newvertex) > 0.0;
+ }
+ else if ((farvertex == m->infvertex1) || (farvertex == m->infvertex2)
+ || (farvertex == m->infvertex3)) {
+ /* `farvertex' is infinitely distant and cannot be inside */
+ /* the circumcircle of the triangle `horiz'. */
+ doflip = 0;
+ }
+ else {
+ /* Test whether the edge is locally Delaunay. */
+ doflip = incircle(m, b, leftvertex, newvertex, rightvertex, farvertex) > 0.0;
+ }
+ if (doflip) {
+ /* We made it! Flip the edge `horiz' by rotating its containing */
+ /* quadrilateral (the two triangles adjacent to `horiz'). */
+ /* Identify the casing of the quadrilateral. */
+ lprev(top, topleft);
+ sym(topleft, toplcasing);
+ lnext(top, topright);
+ sym(topright, toprcasing);
+ lnext(horiz, botleft);
+ sym(botleft, botlcasing);
+ lprev(horiz, botright);
+ sym(botright, botrcasing);
+ /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+ bond(topleft, botlcasing);
+ bond(botleft, botrcasing);
+ bond(botright, toprcasing);
+ bond(topright, toplcasing);
+ if (m->checksegments) {
+ /* Check for subsegments and rebond them to the quadrilateral. */
+ tspivot(topleft, toplsubseg);
+ tspivot(botleft, botlsubseg);
+ tspivot(botright, botrsubseg);
+ tspivot(topright, toprsubseg);
+ if (toplsubseg.ss == m->dummysub) {
+ tsdissolve(topright);
+ }
+ else {
+ tsbond(topright, toplsubseg);
+ }
+ if (botlsubseg.ss == m->dummysub) {
+ tsdissolve(topleft);
+ }
+ else {
+ tsbond(topleft, botlsubseg);
+ }
+ if (botrsubseg.ss == m->dummysub) {
+ tsdissolve(botleft);
+ }
+ else {
+ tsbond(botleft, botrsubseg);
+ }
+ if (toprsubseg.ss == m->dummysub) {
+ tsdissolve(botright);
+ }
+ else {
+ tsbond(botright, toprsubseg);
+ }
+ }
+ /* New vertex assignments for the rotated quadrilateral. */
+ setorg(horiz, farvertex);
+ setdest(horiz, newvertex);
+ setapex(horiz, rightvertex);
+ setorg(top, newvertex);
+ setdest(top, farvertex);
+ setapex(top, leftvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Take the average of the two triangles' attributes. */
+ attrib = 0.5 * (elemattribute(top, i) + elemattribute(horiz, i));
+ setelemattribute(top, i, attrib);
+ setelemattribute(horiz, i, attrib);
+ }
+ if (b->vararea) {
+ if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) {
+ area = -1.0;
+ }
+ else {
+ /* Take the average of the two triangles' area constraints. */
+ /* This prevents small area constraints from migrating a */
+ /* long, long way from their original location due to flips. */
+ area = 0.5 * (areabound(top) + areabound(horiz));
+ }
+ setareabound(top, area);
+ setareabound(horiz, area);
+ }
+
+ if (m->checkquality) {
+ newflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+ newflip->flippedtri = encode(horiz);
+ newflip->prevflip = m->lastflip;
+ m->lastflip = newflip;
+ }
+
+#ifdef SELF_CHECK
+ if (newvertex != (vertex) NULL)
+ {
+ if (counterclockwise(m, b, leftvertex, newvertex, rightvertex) <
+ 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to edge flip (bottom).\n");
+ }
+ /* The following test has been removed because constrainededge() */
+ /* sometimes generates inverted triangles that insertvertex() */
+ /* removes. */
+ /*
+ if (counterclockwise(m, b, rightvertex, farvertex, leftvertex) <
+ 0.0) {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to edge flip (top).\n");
+ }
+ */
+ if (counterclockwise(m, b, farvertex, leftvertex, newvertex) <
+ 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after edge flip (left).\n");
+ }
+ if (counterclockwise(m, b, newvertex, rightvertex, farvertex) <
+ 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after edge flip (right).\n");
+ }
+ }
+#endif /* SELF_CHECK */
+ if (b->verbose > 2) {
+ printf(" Edge flip results in left ");
+ lnextself(topleft);
+ printtriangle(m, b, &topleft);
+ printf(" and right ");
+ printtriangle(m, b, &horiz);
+ }
+ /* On the next iterations, consider the two edges that were */
+ /* exposed (this is, are now visible to the newly inserted */
+ /* vertex) by the edge flip. */
+ lprevself(horiz);
+ leftvertex = farvertex;
+ }
+ }
+ }
+ if (!doflip) {
+ /* The handle `horiz' is accepted as locally Delaunay. */
+#ifndef CDT_ONLY
+ if (triflaws)
+ {
+ /* Check the triangle `horiz' for quality. */
+ testtriangle(m, b, &horiz);
+ }
+#endif /* not CDT_ONLY */
+ /* Look for the next edge around the newly inserted vertex. */
+ lnextself(horiz);
+ sym(horiz, testtri);
+ /* Check for finishing a complete revolution about the new vertex, or */
+ /* falling outside of the triangulation. The latter will happen */
+ /* when a vertex is inserted at a boundary. */
+ if ((leftvertex == first) || (testtri.tri == m->dummytri)) {
+ /* We're done. Return a triangle whose origin is the new vertex. */
+ lnext(horiz, *searchtri);
+ lnext(horiz, m->recenttri);
+ return success;
+ }
+ /* Finish finding the next edge around the newly inserted vertex. */
+ lnext(testtri, horiz);
+ rightvertex = leftvertex;
+ dest(horiz, leftvertex);
+ }
+ }
+}
+
+/********* Divide-and-conquer Delaunay triangulation begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* The divide-and-conquer bounding box */
+/* */
+/* I originally implemented the divide-and-conquer and incremental Delaunay */
+/* triangulations using the edge-based data structure presented by Guibas */
+/* and Stolfi. Switching to a triangle-based data structure doubled the */
+/* speed. However, I had to think of a few extra tricks to maintain the */
+/* elegance of the original algorithms. */
+/* */
+/* The "bounding box" used by my variant of the divide-and-conquer */
+/* algorithm uses one triangle for each edge of the convex hull of the */
+/* triangulation. These bounding triangles all share a common apical */
+/* vertex, which is represented by NULL and which represents nothing. */
+/* The bounding triangles are linked in a circular fan about this NULL */
+/* vertex, and the edges on the convex hull of the triangulation appear */
+/* opposite the NULL vertex. You might find it easiest to imagine that */
+/* the NULL vertex is a point in 3D space behind the center of the */
+/* triangulation, and that the bounding triangles form a sort of cone. */
+/* */
+/* This bounding box makes it easy to represent degenerate cases. For */
+/* instance, the triangulation of two vertices is a single edge. This edge */
+/* is represented by two bounding box triangles, one on each "side" of the */
+/* edge. These triangles are also linked together in a fan about the NULL */
+/* vertex. */
+/* */
+/* The bounding box also makes it easy to traverse the convex hull, as the */
+/* divide-and-conquer algorithm needs to do. */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* */
+/* vertexsort() Sort an array of vertices by x-coordinate, using the */
+/* y-coordinate as a secondary key. */
+/* */
+/* Uses quicksort. Randomized O(n log n) time. No, I did not make any of */
+/* the usual quicksort mistakes. */
+/* */
+/*****************************************************************************/
+
+void vertexsort(vertex *sortarray, int arraysize) {
+ int left, right;
+ int pivot;
+ REAL pivotx, pivoty;
+ vertex temp;
+
+ if (arraysize == 2) {
+ /* Recursive base case. */
+ if ((sortarray[0][0] > sortarray[1][0])
+ || ((sortarray[0][0] == sortarray[1][0]) && (sortarray[0][1] > sortarray[1][1]))) {
+ temp = sortarray[1];
+ sortarray[1] = sortarray[0];
+ sortarray[0] = temp;
+ }
+ return;
+ }
+ /* Choose a random pivot to split the array. */
+ pivot = (int) randomnation((unsigned int) arraysize);
+ pivotx = sortarray[pivot][0];
+ pivoty = sortarray[pivot][1];
+ /* Split the array. */
+ left = -1;
+ right = arraysize;
+ while (left < right) {
+ /* Search for a vertex whose x-coordinate is too large for the left. */
+ do {
+ left++;
+ } while ((left <= right)
+ && ((sortarray[left][0] < pivotx)
+ || ((sortarray[left][0] == pivotx) && (sortarray[left][1] < pivoty))));
+ /* Search for a vertex whose x-coordinate is too small for the right. */
+ do {
+ right--;
+ } while ((left <= right)
+ && ((sortarray[right][0] > pivotx)
+ || ((sortarray[right][0] == pivotx) && (sortarray[right][1] > pivoty))));
+ if (left < right) {
+ /* Swap the left and right vertices. */
+ temp = sortarray[left];
+ sortarray[left] = sortarray[right];
+ sortarray[right] = temp;
+ }
+ }
+ if (left > 1) {
+ /* Recursively sort the left subset. */
+ vertexsort(sortarray, left);
+ }
+ if (right < arraysize - 2) {
+ /* Recursively sort the right subset. */
+ vertexsort(&sortarray[right + 1], arraysize - right - 1);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* vertexmedian() An order statistic algorithm, almost. Shuffles an */
+/* array of vertices so that the first `median' vertices */
+/* occur lexicographically before the remaining vertices. */
+/* */
+/* Uses the x-coordinate as the primary key if axis == 0; the y-coordinate */
+/* if axis == 1. Very similar to the vertexsort() procedure, but runs in */
+/* randomized linear time. */
+/* */
+/*****************************************************************************/
+
+void vertexmedian(vertex *sortarray, int arraysize, int median, int axis) {
+ int left, right;
+ int pivot;
+ REAL pivot1, pivot2;
+ vertex temp;
+
+ if (arraysize == 2) {
+ /* Recursive base case. */
+ if ((sortarray[0][axis] > sortarray[1][axis])
+ || ((sortarray[0][axis] == sortarray[1][axis])
+ && (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) {
+ temp = sortarray[1];
+ sortarray[1] = sortarray[0];
+ sortarray[0] = temp;
+ }
+ return;
+ }
+ /* Choose a random pivot to split the array. */
+ pivot = (int) randomnation((unsigned int) arraysize);
+ pivot1 = sortarray[pivot][axis];
+ pivot2 = sortarray[pivot][1 - axis];
+ /* Split the array. */
+ left = -1;
+ right = arraysize;
+ while (left < right) {
+ /* Search for a vertex whose x-coordinate is too large for the left. */
+ do {
+ left++;
+ } while ((left <= right)
+ && ((sortarray[left][axis] < pivot1)
+ || ((sortarray[left][axis] == pivot1) && (sortarray[left][1 - axis] < pivot2))));
+ /* Search for a vertex whose x-coordinate is too small for the right. */
+ do {
+ right--;
+ } while ((left <= right)
+ && ((sortarray[right][axis] > pivot1)
+ || ((sortarray[right][axis] == pivot1) && (sortarray[right][1 - axis] > pivot2))));
+ if (left < right) {
+ /* Swap the left and right vertices. */
+ temp = sortarray[left];
+ sortarray[left] = sortarray[right];
+ sortarray[right] = temp;
+ }
+ }
+ /* Unlike in vertexsort(), at most one of the following */
+ /* conditionals is true. */
+ if (left > median) {
+ /* Recursively shuffle the left subset. */
+ vertexmedian(sortarray, left, median, axis);
+ }
+ if (right < median - 1) {
+ /* Recursively shuffle the right subset. */
+ vertexmedian(&sortarray[right + 1], arraysize - right - 1, median - right - 1, axis);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* alternateaxes() Sorts the vertices as appropriate for the divide-and- */
+/* conquer algorithm with alternating cuts. */
+/* */
+/* Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1. */
+/* For the base case, subsets containing only two or three vertices are */
+/* always sorted by x-coordinate. */
+/* */
+/*****************************************************************************/
+
+void alternateaxes(vertex *sortarray, int arraysize, int axis) {
+ int divider;
+
+ divider = arraysize >> 1;
+ if (arraysize <= 3) {
+ /* Recursive base case: subsets of two or three vertices will be */
+ /* handled specially, and should always be sorted by x-coordinate. */
+ axis = 0;
+ }
+ /* Partition with a horizontal or vertical cut. */
+ vertexmedian(sortarray, arraysize, divider, axis);
+ /* Recursively partition the subsets with a cross cut. */
+ if (arraysize - divider >= 2) {
+ if (divider >= 2) {
+ alternateaxes(sortarray, divider, 1 - axis);
+ }
+ alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* mergehulls() Merge two adjacent Delaunay triangulations into a */
+/* single Delaunay triangulation. */
+/* */
+/* This is similar to the algorithm given by Guibas and Stolfi, but uses */
+/* a triangle-based, rather than edge-based, data structure. */
+/* */
+/* The algorithm walks up the gap between the two triangulations, knitting */
+/* them together. As they are merged, some of their bounding triangles */
+/* are converted into real triangles of the triangulation. The procedure */
+/* pulls each hull's bounding triangles apart, then knits them together */
+/* like the teeth of two gears. The Delaunay property determines, at each */
+/* step, whether the next "tooth" is a bounding triangle of the left hull */
+/* or the right. When a bounding triangle becomes real, its apex is */
+/* changed from NULL to a real vertex. */
+/* */
+/* Only two new triangles need to be allocated. These become new bounding */
+/* triangles at the top and bottom of the seam. They are used to connect */
+/* the remaining bounding triangles (those that have not been converted */
+/* into real triangles) into a single fan. */
+/* */
+/* On entry, `farleft' and `innerleft' are bounding triangles of the left */
+/* triangulation. The origin of `farleft' is the leftmost vertex, and */
+/* the destination of `innerleft' is the rightmost vertex of the */
+/* triangulation. Similarly, `innerright' and `farright' are bounding */
+/* triangles of the right triangulation. The origin of `innerright' and */
+/* destination of `farright' are the leftmost and rightmost vertices. */
+/* */
+/* On completion, the origin of `farleft' is the leftmost vertex of the */
+/* merged triangulation, and the destination of `farright' is the rightmost */
+/* vertex. */
+/* */
+/*****************************************************************************/
+
+void mergehulls(struct mesh *m, struct behavior *b, struct otri *farleft, struct otri *innerleft,
+ struct otri *innerright, struct otri *farright, int axis) {
+ struct otri leftcand, rightcand;
+ struct otri baseedge;
+ struct otri nextedge;
+ struct otri sidecasing, topcasing, outercasing;
+ struct otri checkedge;
+ vertex innerleftdest;
+ vertex innerrightorg;
+ vertex innerleftapex, innerrightapex;
+ vertex farleftpt, farrightpt;
+ vertex farleftapex, farrightapex;
+ vertex lowerleft, lowerright;
+ vertex upperleft, upperright;
+ vertex nextapex;
+ vertex checkvertex;
+ int changemade;
+ int badedge;
+ int leftfinished, rightfinished;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ dest(*innerleft, innerleftdest);
+ apex(*innerleft, innerleftapex);
+ org(*innerright, innerrightorg);
+ apex(*innerright, innerrightapex);
+ /* Special treatment for horizontal cuts. */
+ if (b->dwyer && (axis == 1)) {
+ org(*farleft, farleftpt);
+ apex(*farleft, farleftapex);
+ dest(*farright, farrightpt);
+ apex(*farright, farrightapex);
+ /* The pointers to the extremal vertices are shifted to point to the */
+ /* topmost and bottommost vertex of each hull, rather than the */
+ /* leftmost and rightmost vertices. */
+ while (farleftapex[1] < farleftpt[1]) {
+ lnextself(*farleft);
+ symself(*farleft);
+ farleftpt = farleftapex;
+ apex(*farleft, farleftapex);
+ }
+ sym(*innerleft, checkedge);
+ apex(checkedge, checkvertex);
+ while (checkvertex[1] > innerleftdest[1]) {
+ lnext(checkedge, *innerleft);
+ innerleftapex = innerleftdest;
+ innerleftdest = checkvertex;
+ sym(*innerleft, checkedge);
+ apex(checkedge, checkvertex);
+ }
+ while (innerrightapex[1] < innerrightorg[1]) {
+ lnextself(*innerright);
+ symself(*innerright);
+ innerrightorg = innerrightapex;
+ apex(*innerright, innerrightapex);
+ }
+ sym(*farright, checkedge);
+ apex(checkedge, checkvertex);
+ while (checkvertex[1] > farrightpt[1]) {
+ lnext(checkedge, *farright);
+ farrightapex = farrightpt;
+ farrightpt = checkvertex;
+ sym(*farright, checkedge);
+ apex(checkedge, checkvertex);
+ }
+ }
+ /* Find a line tangent to and below both hulls. */
+ do {
+ changemade = 0;
+ /* Make innerleftdest the "bottommost" vertex of the left hull. */
+ if (counterclockwise(m, b, innerleftdest, innerleftapex, innerrightorg) > 0.0) {
+ lprevself(*innerleft);
+ symself(*innerleft);
+ innerleftdest = innerleftapex;
+ apex(*innerleft, innerleftapex);
+ changemade = 1;
+ }
+ /* Make innerrightorg the "bottommost" vertex of the right hull. */
+ if (counterclockwise(m, b, innerrightapex, innerrightorg, innerleftdest) > 0.0) {
+ lnextself(*innerright);
+ symself(*innerright);
+ innerrightorg = innerrightapex;
+ apex(*innerright, innerrightapex);
+ changemade = 1;
+ }
+ } while (changemade);
+ /* Find the two candidates to be the next "gear tooth." */
+ sym(*innerleft, leftcand);
+ sym(*innerright, rightcand);
+ /* Create the bottom new bounding triangle. */
+ maketriangle(m, b, &baseedge);
+ /* Connect it to the bounding boxes of the left and right triangulations. */
+ bond(baseedge, *innerleft);
+ lnextself(baseedge);
+ bond(baseedge, *innerright);
+ lnextself(baseedge);
+ setorg(baseedge, innerrightorg);
+ setdest(baseedge, innerleftdest);
+ /* Apex is intentionally left NULL. */
+ if (b->verbose > 2) {
+ printf(" Creating base bounding ");
+ printtriangle(m, b, &baseedge);
+ }
+ /* Fix the extreme triangles if necessary. */
+ org(*farleft, farleftpt);
+ if (innerleftdest == farleftpt) {
+ lnext(baseedge, *farleft);
+ }
+ dest(*farright, farrightpt);
+ if (innerrightorg == farrightpt) {
+ lprev(baseedge, *farright);
+ }
+ /* The vertices of the current knitting edge. */
+ lowerleft = innerleftdest;
+ lowerright = innerrightorg;
+ /* The candidate vertices for knitting. */
+ apex(leftcand, upperleft);
+ apex(rightcand, upperright);
+ /* Walk up the gap between the two triangulations, knitting them together. */
+ while (1) {
+ /* Have we reached the top? (This isn't quite the right question, */
+ /* because even though the left triangulation might seem finished now, */
+ /* moving up on the right triangulation might reveal a new vertex of */
+ /* the left triangulation. And vice-versa.) */
+ leftfinished = counterclockwise(m, b, upperleft, lowerleft, lowerright) <= 0.0;
+ rightfinished = counterclockwise(m, b, upperright, lowerleft, lowerright) <= 0.0;
+ if (leftfinished && rightfinished) {
+ /* Create the top new bounding triangle. */
+ maketriangle(m, b, &nextedge);
+ setorg(nextedge, lowerleft);
+ setdest(nextedge, lowerright);
+ /* Apex is intentionally left NULL. */
+ /* Connect it to the bounding boxes of the two triangulations. */
+ bond(nextedge, baseedge);
+ lnextself(nextedge);
+ bond(nextedge, rightcand);
+ lnextself(nextedge);
+ bond(nextedge, leftcand);
+ if (b->verbose > 2) {
+ printf(" Creating top bounding ");
+ printtriangle(m, b, &nextedge);
+ }
+ /* Special treatment for horizontal cuts. */
+ if (b->dwyer && (axis == 1)) {
+ org(*farleft, farleftpt);
+ apex(*farleft, farleftapex);
+ dest(*farright, farrightpt);
+ apex(*farright, farrightapex);
+ sym(*farleft, checkedge);
+ apex(checkedge, checkvertex);
+ /* The pointers to the extremal vertices are restored to the */
+ /* leftmost and rightmost vertices (rather than topmost and */
+ /* bottommost). */
+ while (checkvertex[0] < farleftpt[0]) {
+ lprev(checkedge, *farleft);
+ farleftapex = farleftpt;
+ farleftpt = checkvertex;
+ sym(*farleft, checkedge);
+ apex(checkedge, checkvertex);
+ }
+ while (farrightapex[0] > farrightpt[0]) {
+ lprevself(*farright);
+ symself(*farright);
+ farrightpt = farrightapex;
+ apex(*farright, farrightapex);
+ }
+ }
+ return;
+ }
+ /* Consider eliminating edges from the left triangulation. */
+ if (!leftfinished) {
+ /* What vertex would be exposed if an edge were deleted? */
+ lprev(leftcand, nextedge);
+ symself(nextedge);
+ apex(nextedge, nextapex);
+ /* If nextapex is NULL, then no vertex would be exposed; the */
+ /* triangulation would have been eaten right through. */
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperleft, nextapex) > 0.0;
+ while (badedge) {
+ /* Eliminate the edge with an edge flip. As a result, the */
+ /* left triangulation will have one more boundary triangle. */
+ lnextself(nextedge);
+ sym(nextedge, topcasing);
+ lnextself(nextedge);
+ sym(nextedge, sidecasing);
+ bond(nextedge, topcasing);
+ bond(leftcand, sidecasing);
+ lnextself(leftcand);
+ sym(leftcand, outercasing);
+ lprevself(nextedge);
+ bond(nextedge, outercasing);
+ /* Correct the vertices to reflect the edge flip. */
+ setorg(leftcand, lowerleft);
+ setdest(leftcand, NULL);
+ setapex(leftcand, nextapex);
+ setorg(nextedge, NULL);
+ setdest(nextedge, upperleft);
+ setapex(nextedge, nextapex);
+ /* Consider the newly exposed vertex. */
+ upperleft = nextapex;
+ /* What vertex would be exposed if another edge were deleted? */
+ otricopy(sidecasing, nextedge);
+ apex(nextedge, nextapex);
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperleft, nextapex) > 0.0;
+ }
+ else {
+ /* Avoid eating right through the triangulation. */
+ badedge = 0;
+ }
+ }
+ }
+ }
+ /* Consider eliminating edges from the right triangulation. */
+ if (!rightfinished) {
+ /* What vertex would be exposed if an edge were deleted? */
+ lnext(rightcand, nextedge);
+ symself(nextedge);
+ apex(nextedge, nextapex);
+ /* If nextapex is NULL, then no vertex would be exposed; the */
+ /* triangulation would have been eaten right through. */
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperright, nextapex) > 0.0;
+ while (badedge) {
+ /* Eliminate the edge with an edge flip. As a result, the */
+ /* right triangulation will have one more boundary triangle. */
+ lprevself(nextedge);
+ sym(nextedge, topcasing);
+ lprevself(nextedge);
+ sym(nextedge, sidecasing);
+ bond(nextedge, topcasing);
+ bond(rightcand, sidecasing);
+ lprevself(rightcand);
+ sym(rightcand, outercasing);
+ lnextself(nextedge);
+ bond(nextedge, outercasing);
+ /* Correct the vertices to reflect the edge flip. */
+ setorg(rightcand, NULL);
+ setdest(rightcand, lowerright);
+ setapex(rightcand, nextapex);
+ setorg(nextedge, upperright);
+ setdest(nextedge, NULL);
+ setapex(nextedge, nextapex);
+ /* Consider the newly exposed vertex. */
+ upperright = nextapex;
+ /* What vertex would be exposed if another edge were deleted? */
+ otricopy(sidecasing, nextedge);
+ apex(nextedge, nextapex);
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperright, nextapex) > 0.0;
+ }
+ else {
+ /* Avoid eating right through the triangulation. */
+ badedge = 0;
+ }
+ }
+ }
+ }
+ if (leftfinished
+ || (!rightfinished
+ && (incircle(m, b, upperleft, lowerleft, lowerright, upperright) > 0.0))) {
+ /* Knit the triangulations, adding an edge from `lowerleft' */
+ /* to `upperright'. */
+ bond(baseedge, rightcand);
+ lprev(rightcand, baseedge);
+ setdest(baseedge, lowerleft);
+ lowerright = upperright;
+ sym(baseedge, rightcand);
+ apex(rightcand, upperright);
+ }
+ else {
+ /* Knit the triangulations, adding an edge from `upperleft' */
+ /* to `lowerright'. */
+ bond(baseedge, leftcand);
+ lnext(leftcand, baseedge);
+ setorg(baseedge, lowerright);
+ lowerleft = upperleft;
+ sym(baseedge, leftcand);
+ apex(leftcand, upperleft);
+ }
+ if (b->verbose > 2) {
+ printf(" Connecting ");
+ printtriangle(m, b, &baseedge);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* divconqrecurse() Recursively form a Delaunay triangulation by the */
+/* divide-and-conquer method. */
+/* */
+/* Recursively breaks down the problem into smaller pieces, which are */
+/* knitted together by mergehulls(). The base cases (problems of two or */
+/* three vertices) are handled specially here. */
+/* */
+/* On completion, `farleft' and `farright' are bounding triangles such that */
+/* the origin of `farleft' is the leftmost vertex (breaking ties by */
+/* choosing the highest leftmost vertex), and the destination of */
+/* `farright' is the rightmost vertex (breaking ties by choosing the */
+/* lowest rightmost vertex). */
+/* */
+/*****************************************************************************/
+
+void divconqrecurse(struct mesh *m, struct behavior *b, vertex *sortarray, int vertices, int axis,
+ struct otri *farleft, struct otri *farright) {
+ struct otri midtri, tri1, tri2, tri3;
+ struct otri innerleft, innerright;
+ REAL area;
+ int divider;
+
+ if (b->verbose > 2) {
+ printf(" Triangulating %d vertices.\n", vertices);
+ }
+ if (vertices == 2) {
+ /* The triangulation of two vertices is an edge. An edge is */
+ /* represented by two bounding triangles. */
+ maketriangle(m, b, farleft);
+ setorg(*farleft, sortarray[0]);
+ setdest(*farleft, sortarray[1]);
+ /* The apex is intentionally left NULL. */
+ maketriangle(m, b, farright);
+ setorg(*farright, sortarray[1]);
+ setdest(*farright, sortarray[0]);
+ /* The apex is intentionally left NULL. */
+ bond(*farleft, *farright);
+ lprevself(*farleft);
+ lnextself(*farright);
+ bond(*farleft, *farright);
+ lprevself(*farleft);
+ lnextself(*farright);
+ bond(*farleft, *farright);
+ if (b->verbose > 2) {
+ printf(" Creating ");
+ printtriangle(m, b, farleft);
+ printf(" Creating ");
+ printtriangle(m, b, farright);
+ }
+ /* Ensure that the origin of `farleft' is sortarray[0]. */
+ lprev(*farright, *farleft);
+ return;
+ }
+ else if (vertices == 3) {
+ /* The triangulation of three vertices is either a triangle (with */
+ /* three bounding triangles) or two edges (with four bounding */
+ /* triangles). In either case, four triangles are created. */
+ maketriangle(m, b, &midtri);
+ maketriangle(m, b, &tri1);
+ maketriangle(m, b, &tri2);
+ maketriangle(m, b, &tri3);
+ area = counterclockwise(m, b, sortarray[0], sortarray[1], sortarray[2]);
+ if (area == 0.0) {
+ /* Three collinear vertices; the triangulation is two edges. */
+ setorg(midtri, sortarray[0]);
+ setdest(midtri, sortarray[1]);
+ setorg(tri1, sortarray[1]);
+ setdest(tri1, sortarray[0]);
+ setorg(tri2, sortarray[2]);
+ setdest(tri2, sortarray[1]);
+ setorg(tri3, sortarray[1]);
+ setdest(tri3, sortarray[2]);
+ /* All apices are intentionally left NULL. */
+ bond(midtri, tri1);
+ bond(tri2, tri3);
+ lnextself(midtri);
+ lprevself(tri1);
+ lnextself(tri2);
+ lprevself(tri3);
+ bond(midtri, tri3);
+ bond(tri1, tri2);
+ lnextself(midtri);
+ lprevself(tri1);
+ lnextself(tri2);
+ lprevself(tri3);
+ bond(midtri, tri1);
+ bond(tri2, tri3);
+ /* Ensure that the origin of `farleft' is sortarray[0]. */
+ otricopy(tri1, *farleft);
+ /* Ensure that the destination of `farright' is sortarray[2]. */
+ otricopy(tri2, *farright);
+ }
+ else {
+ /* The three vertices are not collinear; the triangulation is one */
+ /* triangle, namely `midtri'. */
+ setorg(midtri, sortarray[0]);
+ setdest(tri1, sortarray[0]);
+ setorg(tri3, sortarray[0]);
+ /* Apices of tri1, tri2, and tri3 are left NULL. */
+ if (area > 0.0) {
+ /* The vertices are in counterclockwise order. */
+ setdest(midtri, sortarray[1]);
+ setorg(tri1, sortarray[1]);
+ setdest(tri2, sortarray[1]);
+ setapex(midtri, sortarray[2]);
+ setorg(tri2, sortarray[2]);
+ setdest(tri3, sortarray[2]);
+ }
+ else {
+ /* The vertices are in clockwise order. */
+ setdest(midtri, sortarray[2]);
+ setorg(tri1, sortarray[2]);
+ setdest(tri2, sortarray[2]);
+ setapex(midtri, sortarray[1]);
+ setorg(tri2, sortarray[1]);
+ setdest(tri3, sortarray[1]);
+ }
+ /* The topology does not depend on how the vertices are ordered. */
+ bond(midtri, tri1);
+ lnextself(midtri);
+ bond(midtri, tri2);
+ lnextself(midtri);
+ bond(midtri, tri3);
+ lprevself(tri1);
+ lnextself(tri2);
+ bond(tri1, tri2);
+ lprevself(tri1);
+ lprevself(tri3);
+ bond(tri1, tri3);
+ lnextself(tri2);
+ lprevself(tri3);
+ bond(tri2, tri3);
+ /* Ensure that the origin of `farleft' is sortarray[0]. */
+ otricopy(tri1, *farleft);
+ /* Ensure that the destination of `farright' is sortarray[2]. */
+ if (area > 0.0) {
+ otricopy(tri2, *farright);
+ }
+ else {
+ lnext(*farleft, *farright);
+ }
+ }
+ if (b->verbose > 2) {
+ printf(" Creating ");
+ printtriangle(m, b, &midtri);
+ printf(" Creating ");
+ printtriangle(m, b, &tri1);
+ printf(" Creating ");
+ printtriangle(m, b, &tri2);
+ printf(" Creating ");
+ printtriangle(m, b, &tri3);
+ }
+ return;
+ }
+ else {
+ /* Split the vertices in half. */
+ divider = vertices >> 1;
+ /* Recursively triangulate each half. */
+ divconqrecurse(m, b, sortarray, divider, 1 - axis, farleft, &innerleft);
+ divconqrecurse(m, b, &sortarray[divider], vertices - divider, 1 - axis, &innerright,
+ farright);
+ if (b->verbose > 1) {
+ printf(" Joining triangulations with %d and %d vertices.\n", divider, vertices - divider);
+ }
+ /* Merge the two triangulations into one. */
+ mergehulls(m, b, farleft, &innerleft, &innerright, farright, axis);
+ }
+}
+
+long removeghosts(struct mesh *m, struct behavior *b, struct otri *startghost) {
+ struct otri searchedge;
+ struct otri dissolveedge;
+ struct otri deadtriangle;
+ vertex markorg;
+ long hullsize;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (b->verbose) {
+ printf(" Removing ghost triangles.\n");
+ }
+ /* Find an edge on the convex hull to start point location from. */
+ lprev(*startghost, searchedge);
+ symself(searchedge);
+ m->dummytri[0] = encode(searchedge);
+ /* Remove the bounding box and count the convex hull edges. */
+ otricopy(*startghost, dissolveedge);
+ hullsize = 0;
+ do {
+ hullsize++;
+ lnext(dissolveedge, deadtriangle);
+ lprevself(dissolveedge);
+ symself(dissolveedge);
+ /* If no PSLG is involved, set the boundary markers of all the vertices */
+ /* on the convex hull. If a PSLG is used, this step is done later. */
+ if (!b->poly) {
+ /* Watch out for the case where all the input vertices are collinear. */
+ if (dissolveedge.tri != m->dummytri) {
+ org(dissolveedge, markorg);
+ if (vertexmark(markorg) == 0) {
+ setvertexmark(markorg, 1);
+ }
+ }
+ }
+ /* Remove a bounding triangle from a convex hull triangle. */
+ dissolve(dissolveedge);
+ /* Find the next bounding triangle. */
+ sym(deadtriangle, dissolveedge);
+ /* Delete the bounding triangle. */
+ triangledealloc(m, deadtriangle.tri);
+ } while (!otriequal(dissolveedge, *startghost));
+ return hullsize;
+}
+
+/*****************************************************************************/
+/* */
+/* divconqdelaunay() Form a Delaunay triangulation by the divide-and- */
+/* conquer method. */
+/* */
+/* Sorts the vertices, calls a recursive procedure to triangulate them, and */
+/* removes the bounding box, setting boundary markers as appropriate. */
+/* */
+/*****************************************************************************/
+
+long divconqdelaunay(struct mesh *m, struct behavior *b) {
+ vertex *sortarray;
+ struct otri hullleft, hullright;
+ int divider;
+ int i, j;
+
+ if (b->verbose) {
+ printf(" Sorting vertices.\n");
+ }
+
+ /* Allocate an array of pointers to vertices for sorting. */
+ sortarray = (vertex *) trimalloc(m->invertices * (int) sizeof(vertex));
+ traversalinit(&m->vertices);
+ for (i = 0; i < m->invertices; i++) {
+ sortarray[i] = vertextraverse(m);
+ }
+ /* Sort the vertices. */
+ vertexsort(sortarray, m->invertices);
+ /* Discard duplicate vertices, which can really mess up the algorithm. */
+ i = 0;
+ for (j = 1; j < m->invertices; j++) {
+ if ((sortarray[i][0] == sortarray[j][0]) && (sortarray[i][1] == sortarray[j][1])) {
+ if (!b->quiet) {
+ printf(
+ "Warning: A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n", sortarray[j][0], sortarray[j][1]);
+ }
+ setvertextype(sortarray[j], UNDEADVERTEX);
+ m->undeads++;
+ }
+ else {
+ i++;
+ sortarray[i] = sortarray[j];
+ }
+ }
+ i++;
+ if (b->dwyer) {
+ /* Re-sort the array of vertices to accommodate alternating cuts. */
+ divider = i >> 1;
+ if (i - divider >= 2) {
+ if (divider >= 2) {
+ alternateaxes(sortarray, divider, 1);
+ }
+ alternateaxes(&sortarray[divider], i - divider, 1);
+ }
+ }
+
+ if (b->verbose) {
+ printf(" Forming triangulation.\n");
+ }
+
+ /* Form the Delaunay triangulation. */
+ divconqrecurse(m, b, sortarray, i, 0, &hullleft, &hullright);
+ trifree((VOID *) sortarray);
+
+ return removeghosts(m, b, &hullleft);
+}
+
+/** **/
+/** **/
+/********* Divide-and-conquer Delaunay triangulation ends here *********/
+
+/********* General mesh construction routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* delaunay() Form a Delaunay triangulation. */
+/* */
+/*****************************************************************************/
+
+long delaunay(struct mesh *m, struct behavior *b) {
+ long hulledges;
+
+ m->eextras = 0;
+ initializetrisubpools(m, b);
+
+#ifdef REDUCED
+ if (!b->quiet) {
+ printf( "Constructing Delaunay triangulation by divide-and-conquer method.\n");
+ }
+ hulledges = divconqdelaunay(m, b);
+#else /* not REDUCED */
+ if (!b->quiet)
+ {
+ printf("Constructing Delaunay triangulation ");
+ if (b->incremental)
+ {
+ printf("by incremental method.\n");
+ }
+ else if (b->sweepline)
+ {
+ printf("by sweepline method.\n");
+ }
+ else
+ {
+ printf("by divide-and-conquer method.\n");
+ }
+ }
+ if (b->incremental)
+ {
+ hulledges = incrementaldelaunay(m, b);
+ }
+ else if (b->sweepline)
+ {
+ hulledges = sweeplinedelaunay(m, b);
+ }
+ else
+ {
+ hulledges = divconqdelaunay(m, b);
+ }
+#endif /* not REDUCED */
+
+ if (m->triangles.items == 0) {
+ /* The input vertices were all collinear, so there are no triangles. */
+ return 0l;
+ }
+ else {
+ return hulledges;
+ }
+}
+
+/** **/
+/** **/
+/********* General mesh construction routines end here *********/
+
+/********* Segment insertion begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* finddirection() Find the first triangle on the path from one point */
+/* to another. */
+/* */
+/* Finds the triangle that intersects a line segment drawn from the */
+/* origin of `searchtri' to the point `searchpoint', and returns the result */
+/* in `searchtri'. The origin of `searchtri' does not change, even though */
+/* the triangle returned may differ from the one passed in. This routine */
+/* is used to find the direction to move in to get from one point to */
+/* another. */
+/* */
+/* The return value notes whether the destination or apex of the found */
+/* triangle is collinear with the two points in question. */
+/* */
+/*****************************************************************************/
+
+enum finddirectionresult finddirection(struct mesh *m, struct behavior *b, struct otri *searchtri,
+ vertex searchpoint) {
+ struct otri checktri;
+ vertex startvertex;
+ vertex leftvertex, rightvertex;
+ REAL leftccw, rightccw;
+ int leftflag, rightflag;
+ triangle ptr; /* Temporary variable used by onext() and oprev(). */
+
+ org(*searchtri, startvertex);
+ dest(*searchtri, rightvertex);
+ apex(*searchtri, leftvertex);
+ /* Is `searchpoint' to the left? */
+ leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex);
+ leftflag = leftccw > 0.0;
+ /* Is `searchpoint' to the right? */
+ rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex);
+ rightflag = rightccw > 0.0;
+ if (leftflag && rightflag) {
+ /* `searchtri' faces directly away from `searchpoint'. We could go left */
+ /* or right. Ask whether it's a triangle or a boundary on the left. */
+ onext(*searchtri, checktri);
+ if (checktri.tri == m->dummytri) {
+ leftflag = 0;
+ }
+ else {
+ rightflag = 0;
+ }
+ }
+ while (leftflag) {
+ /* Turn left until satisfied. */
+ onextself(*searchtri);
+ if (searchtri->tri == m->dummytri) {
+ printf("Internal error in finddirection(): Unable to find a\n");
+ printf(" triangle leading from (%.12g, %.12g) to", startvertex[0], startvertex[1]);
+ printf(" (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ internalerror();
+ }
+ apex(*searchtri, leftvertex);
+ rightccw = leftccw;
+ leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex);
+ leftflag = leftccw > 0.0;
+ }
+ while (rightflag) {
+ /* Turn right until satisfied. */
+ oprevself(*searchtri);
+ if (searchtri->tri == m->dummytri) {
+ printf("Internal error in finddirection(): Unable to find a\n");
+ printf(" triangle leading from (%.12g, %.12g) to", startvertex[0], startvertex[1]);
+ printf(" (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ internalerror();
+ }
+ dest(*searchtri, rightvertex);
+ leftccw = rightccw;
+ rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex);
+ rightflag = rightccw > 0.0;
+ }
+ if (leftccw == 0.0) {
+ return LEFTCOLLINEAR;
+ }
+ else if (rightccw == 0.0) {
+ return RIGHTCOLLINEAR;
+ }
+ else {
+ return WITHIN;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* segmentintersection() Find the intersection of an existing segment */
+/* and a segment that is being inserted. Insert */
+/* a vertex at the intersection, splitting an */
+/* existing subsegment. */
+/* */
+/* The segment being inserted connects the apex of splittri to endpoint2. */
+/* splitsubseg is the subsegment being split, and MUST adjoin splittri. */
+/* Hence, endpoints of the subsegment being split are the origin and */
+/* destination of splittri. */
+/* */
+/* On completion, splittri is a handle having the newly inserted */
+/* intersection point as its origin, and endpoint1 as its destination. */
+/* */
+/*****************************************************************************/
+
+void segmentintersection(struct mesh *m, struct behavior *b, struct otri *splittri,
+ struct osub *splitsubseg, vertex endpoint2) {
+ struct osub opposubseg;
+ vertex endpoint1;
+ vertex torg, tdest;
+ vertex leftvertex, rightvertex;
+ vertex newvertex;
+ enum insertvertexresult success;
+ //enum finddirectionresult collinear;
+ REAL ex, ey;
+ REAL tx, ty;
+ REAL etx, ety;
+ REAL split, denom;
+ int i;
+ triangle ptr; /* Temporary variable used by onext(). */
+ subseg sptr; /* Temporary variable used by snext(). */
+
+ /* Find the other three segment endpoints. */
+ apex(*splittri, endpoint1);
+ org(*splittri, torg);
+ dest(*splittri, tdest);
+ /* Segment intersection formulae; see the Antonio reference. */
+ tx = tdest[0] - torg[0];
+ ty = tdest[1] - torg[1];
+ ex = endpoint2[0] - endpoint1[0];
+ ey = endpoint2[1] - endpoint1[1];
+ etx = torg[0] - endpoint2[0];
+ ety = torg[1] - endpoint2[1];
+ denom = ty * ex - tx * ey;
+ if (denom == 0.0) {
+ printf("Internal error in segmentintersection():");
+ printf(" Attempt to find intersection of parallel segments.\n");
+ internalerror();
+ return;
+ }
+ split = (ey * etx - ex * ety) / denom;
+ /* Create the new vertex. */
+ newvertex = (vertex) poolalloc(&m->vertices);
+ /* Interpolate its coordinate and attributes. */
+ for (i = 0; i < 2 + m->nextras; i++) {
+ newvertex[i] = torg[i] + split * (tdest[i] - torg[i]);
+ }
+ setvertexmark(newvertex, mark(*splitsubseg));
+ setvertextype(newvertex, INPUTVERTEX);
+ if (b->verbose > 1) {
+ printf(
+ " Splitting subsegment (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", torg[0], torg[1], tdest[0], tdest[1], newvertex[0], newvertex[1]);
+ }
+ /* Insert the intersection vertex. This should always succeed. */
+ success = insertvertex(m, b, newvertex, splittri, splitsubseg, 0, 0);
+ if (success != SUCCESSFULVERTEX) {
+ printf("Internal error in segmentintersection():\n");
+ printf(" Failure to split a segment.\n");
+ internalerror();
+ return;
+ }
+ /* Record a triangle whose origin is the new vertex. */
+ setvertex2tri(newvertex, encode(*splittri));
+ if (m->steinerleft > 0) {
+ m->steinerleft--;
+ }
+
+ /* Divide the segment into two, and correct the segment endpoints. */
+ ssymself(*splitsubseg);
+ spivot(*splitsubseg, opposubseg);
+ sdissolve(*splitsubseg);
+ sdissolve(opposubseg);
+ do {
+ setsegorg(*splitsubseg, newvertex);
+ snextself(*splitsubseg);
+ } while (splitsubseg->ss != m->dummysub);
+ do {
+ setsegorg(opposubseg, newvertex);
+ snextself(opposubseg);
+ } while (opposubseg.ss != m->dummysub);
+
+ /* Inserting the vertex may have caused edge flips. We wish to rediscover */
+ /* the edge connecting endpoint1 to the new intersection vertex. */
+
+ // FIXME collinear =
+ finddirection(m, b, splittri, endpoint1);
+
+ dest(*splittri, rightvertex);
+ apex(*splittri, leftvertex);
+ if ((leftvertex[0] == endpoint1[0]) && (leftvertex[1] == endpoint1[1])) {
+ onextself(*splittri);
+ }
+ else if ((rightvertex[0] != endpoint1[0]) || (rightvertex[1] != endpoint1[1])) {
+ printf("Internal error in segmentintersection():\n");
+ printf(" Topological inconsistency after splitting a segment.\n");
+ internalerror();
+ return;
+ }
+ /* `splittri' should have destination endpoint1. */
+}
+
+/*****************************************************************************/
+/* */
+/* scoutsegment() Scout the first triangle on the path from one endpoint */
+/* to another, and check for completion (reaching the */
+/* second endpoint), a collinear vertex, or the */
+/* intersection of two segments. */
+/* */
+/* Returns one if the entire segment is successfully inserted, and zero if */
+/* the job must be finished by conformingedge() or constrainededge(). */
+/* */
+/* If the first triangle on the path has the second endpoint as its */
+/* destination or apex, a subsegment is inserted and the job is done. */
+/* */
+/* If the first triangle on the path has a destination or apex that lies on */
+/* the segment, a subsegment is inserted connecting the first endpoint to */
+/* the collinear vertex, and the search is continued from the collinear */
+/* vertex. */
+/* */
+/* If the first triangle on the path has a subsegment opposite its origin, */
+/* then there is a segment that intersects the segment being inserted. */
+/* Their intersection vertex is inserted, splitting the subsegment. */
+/* */
+/*****************************************************************************/
+
+int scoutsegment(struct mesh *m, struct behavior *b, struct otri *searchtri, vertex endpoint2,
+ int newmark) {
+ struct otri crosstri;
+ struct osub crosssubseg;
+ vertex leftvertex, rightvertex;
+ enum finddirectionresult collinear;
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ collinear = finddirection(m, b, searchtri, endpoint2);
+ dest(*searchtri, rightvertex);
+ apex(*searchtri, leftvertex);
+ if (((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1]))
+ || ((rightvertex[0] == endpoint2[0]) && (rightvertex[1] == endpoint2[1]))) {
+ /* The segment is already an edge in the mesh. */
+ if ((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1])) {
+ lprevself(*searchtri);
+ }
+ /* Insert a subsegment, if there isn't already one there. */
+ insertsubseg(m, b, searchtri, newmark);
+ return 1;
+ }
+ else if (collinear == LEFTCOLLINEAR) {
+ /* We've collided with a vertex between the segment's endpoints. */
+ /* Make the collinear vertex be the triangle's origin. */
+ lprevself(*searchtri);
+ insertsubseg(m, b, searchtri, newmark);
+ /* Insert the remainder of the segment. */
+ return scoutsegment(m, b, searchtri, endpoint2, newmark);
+ }
+ else if (collinear == RIGHTCOLLINEAR) {
+ /* We've collided with a vertex between the segment's endpoints. */
+ insertsubseg(m, b, searchtri, newmark);
+ /* Make the collinear vertex be the triangle's origin. */
+ lnextself(*searchtri);
+ /* Insert the remainder of the segment. */
+ return scoutsegment(m, b, searchtri, endpoint2, newmark);
+ }
+ else {
+ lnext(*searchtri, crosstri);
+ tspivot(crosstri, crosssubseg);
+ /* Check for a crossing segment. */
+ if (crosssubseg.ss == m->dummysub) {
+ return 0;
+ }
+ else {
+ /* Insert a vertex at the intersection. */
+ segmentintersection(m, b, &crosstri, &crosssubseg, endpoint2);
+ if (error_set)
+ return -1;
+ otricopy(crosstri, *searchtri);
+ insertsubseg(m, b, searchtri, newmark);
+ /* Insert the remainder of the segment. */
+ return scoutsegment(m, b, searchtri, endpoint2, newmark);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* delaunayfixup() Enforce the Delaunay condition at an edge, fanning out */
+/* recursively from an existing vertex. Pay special */
+/* attention to stacking inverted triangles. */
+/* */
+/* This is a support routine for inserting segments into a constrained */
+/* Delaunay triangulation. */
+/* */
+/* The origin of fixuptri is treated as if it has just been inserted, and */
+/* the local Delaunay condition needs to be enforced. It is only enforced */
+/* in one sector, however, that being the angular range defined by */
+/* fixuptri. */
+/* */
+/* This routine also needs to make decisions regarding the "stacking" of */
+/* triangles. (Read the description of constrainededge() below before */
+/* reading on here, so you understand the algorithm.) If the position of */
+/* the new vertex (the origin of fixuptri) indicates that the vertex before */
+/* it on the polygon is a reflex vertex, then "stack" the triangle by */
+/* doing nothing. (fixuptri is an inverted triangle, which is how stacked */
+/* triangles are identified.) */
+/* */
+/* Otherwise, check whether the vertex before that was a reflex vertex. */
+/* If so, perform an edge flip, thereby eliminating an inverted triangle */
+/* (popping it off the stack). The edge flip may result in the creation */
+/* of a new inverted triangle, depending on whether or not the new vertex */
+/* is visible to the vertex three edges behind on the polygon. */
+/* */
+/* If neither of the two vertices behind the new vertex are reflex */
+/* vertices, fixuptri and fartri, the triangle opposite it, are not */
+/* inverted; hence, ensure that the edge between them is locally Delaunay. */
+/* */
+/* `leftside' indicates whether or not fixuptri is to the left of the */
+/* segment being inserted. (Imagine that the segment is pointing up from */
+/* endpoint1 to endpoint2.) */
+/* */
+/*****************************************************************************/
+
+void delaunayfixup(struct mesh *m, struct behavior *b, struct otri *fixuptri, int leftside) {
+ struct otri neartri;
+ struct otri fartri;
+ struct osub faredge;
+ vertex nearvertex, leftvertex, rightvertex, farvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ lnext(*fixuptri, neartri);
+ sym(neartri, fartri);
+ /* Check if the edge opposite the origin of fixuptri can be flipped. */
+ if (fartri.tri == m->dummytri) {
+ return;
+ }
+ tspivot(neartri, faredge);
+ if (faredge.ss != m->dummysub) {
+ return;
+ }
+ /* Find all the relevant vertices. */
+ apex(neartri, nearvertex);
+ org(neartri, leftvertex);
+ dest(neartri, rightvertex);
+ apex(fartri, farvertex);
+ /* Check whether the previous polygon vertex is a reflex vertex. */
+ if (leftside) {
+ if (counterclockwise(m, b, nearvertex, leftvertex, farvertex) <= 0.0) {
+ /* leftvertex is a reflex vertex too. Nothing can */
+ /* be done until a convex section is found. */
+ return;
+ }
+ }
+ else {
+ if (counterclockwise(m, b, farvertex, rightvertex, nearvertex) <= 0.0) {
+ /* rightvertex is a reflex vertex too. Nothing can */
+ /* be done until a convex section is found. */
+ return;
+ }
+ }
+ if (counterclockwise(m, b, rightvertex, leftvertex, farvertex) > 0.0) {
+ /* fartri is not an inverted triangle, and farvertex is not a reflex */
+ /* vertex. As there are no reflex vertices, fixuptri isn't an */
+ /* inverted triangle, either. Hence, test the edge between the */
+ /* triangles to ensure it is locally Delaunay. */
+ if (incircle(m, b, leftvertex, farvertex, rightvertex, nearvertex) <= 0.0) {
+ return;
+ }
+ /* Not locally Delaunay; go on to an edge flip. */
+ } /* else fartri is inverted; remove it from the stack by flipping. */
+ flip(m, b, &neartri);
+ lprevself(*fixuptri);
+ /* Restore the origin of fixuptri after the flip. */
+ /* Recursively process the two triangles that result from the flip. */
+ delaunayfixup(m, b, fixuptri, leftside);
+ delaunayfixup(m, b, &fartri, leftside);
+}
+
+/*****************************************************************************/
+/* */
+/* constrainededge() Force a segment into a constrained Delaunay */
+/* triangulation by deleting the triangles it */
+/* intersects, and triangulating the polygons that */
+/* form on each side of it. */
+/* */
+/* Generates a single subsegment connecting `endpoint1' to `endpoint2'. */
+/* The triangle `starttri' has `endpoint1' as its origin. `newmark' is the */
+/* boundary marker of the segment. */
+/* */
+/* To insert a segment, every triangle whose interior intersects the */
+/* segment is deleted. The union of these deleted triangles is a polygon */
+/* (which is not necessarily monotone, but is close enough), which is */
+/* divided into two polygons by the new segment. This routine's task is */
+/* to generate the Delaunay triangulation of these two polygons. */
+/* */
+/* You might think of this routine's behavior as a two-step process. The */
+/* first step is to walk from endpoint1 to endpoint2, flipping each edge */
+/* encountered. This step creates a fan of edges connected to endpoint1, */
+/* including the desired edge to endpoint2. The second step enforces the */
+/* Delaunay condition on each side of the segment in an incremental manner: */
+/* proceeding along the polygon from endpoint1 to endpoint2 (this is done */
+/* independently on each side of the segment), each vertex is "enforced" */
+/* as if it had just been inserted, but affecting only the previous */
+/* vertices. The result is the same as if the vertices had been inserted */
+/* in the order they appear on the polygon, so the result is Delaunay. */
+/* */
+/* In truth, constrainededge() interleaves these two steps. The procedure */
+/* walks from endpoint1 to endpoint2, and each time an edge is encountered */
+/* and flipped, the newly exposed vertex (at the far end of the flipped */
+/* edge) is "enforced" upon the previously flipped edges, usually affecting */
+/* only one side of the polygon (depending upon which side of the segment */
+/* the vertex falls on). */
+/* */
+/* The algorithm is complicated by the need to handle polygons that are not */
+/* convex. Although the polygon is not necessarily monotone, it can be */
+/* triangulated in a manner similar to the stack-based algorithms for */
+/* monotone polygons. For each reflex vertex (local concavity) of the */
+/* polygon, there will be an inverted triangle formed by one of the edge */
+/* flips. (An inverted triangle is one with negative area - that is, its */
+/* vertices are arranged in clockwise order - and is best thought of as a */
+/* wrinkle in the fabric of the mesh.) Each inverted triangle can be */
+/* thought of as a reflex vertex pushed on the stack, waiting to be fixed */
+/* later. */
+/* */
+/* A reflex vertex is popped from the stack when a vertex is inserted that */
+/* is visible to the reflex vertex. (However, if the vertex behind the */
+/* reflex vertex is not visible to the reflex vertex, a new inverted */
+/* triangle will take its place on the stack.) These details are handled */
+/* by the delaunayfixup() routine above. */
+/* */
+/*****************************************************************************/
+
+void constrainededge(struct mesh *m, struct behavior *b, struct otri *starttri, vertex endpoint2,
+ int newmark) {
+ struct otri fixuptri, fixuptri2;
+ struct osub crosssubseg;
+ vertex endpoint1;
+ vertex farvertex;
+ REAL area;
+ int collision;
+ int done;
+ triangle ptr; /* Temporary variable used by sym() and oprev(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ org(*starttri, endpoint1);
+ lnext(*starttri, fixuptri);
+ flip(m, b, &fixuptri);
+ /* `collision' indicates whether we have found a vertex directly */
+ /* between endpoint1 and endpoint2. */
+ collision = 0;
+ done = 0;
+ do {
+ org(fixuptri, farvertex);
+ /* `farvertex' is the extreme point of the polygon we are "digging" */
+ /* to get from endpoint1 to endpoint2. */
+ if ((farvertex[0] == endpoint2[0]) && (farvertex[1] == endpoint2[1])) {
+ oprev(fixuptri, fixuptri2);
+ /* Enforce the Delaunay condition around endpoint2. */
+ delaunayfixup(m, b, &fixuptri, 0);
+ delaunayfixup(m, b, &fixuptri2, 1);
+ done = 1;
+ }
+ else {
+ /* Check whether farvertex is to the left or right of the segment */
+ /* being inserted, to decide which edge of fixuptri to dig */
+ /* through next. */
+ area = counterclockwise(m, b, endpoint1, endpoint2, farvertex);
+ if (area == 0.0) {
+ /* We've collided with a vertex between endpoint1 and endpoint2. */
+ collision = 1;
+ oprev(fixuptri, fixuptri2);
+ /* Enforce the Delaunay condition around farvertex. */
+ delaunayfixup(m, b, &fixuptri, 0);
+ delaunayfixup(m, b, &fixuptri2, 1);
+ done = 1;
+ }
+ else {
+ if (area > 0.0) { /* farvertex is to the left of the segment. */
+ oprev(fixuptri, fixuptri2);
+ /* Enforce the Delaunay condition around farvertex, on the */
+ /* left side of the segment only. */
+ delaunayfixup(m, b, &fixuptri2, 1);
+ /* Flip the edge that crosses the segment. After the edge is */
+ /* flipped, one of its endpoints is the fan vertex, and the */
+ /* destination of fixuptri is the fan vertex. */
+ lprevself(fixuptri);
+ }
+ else { /* farvertex is to the right of the segment. */
+ delaunayfixup(m, b, &fixuptri, 0);
+ /* Flip the edge that crosses the segment. After the edge is */
+ /* flipped, one of its endpoints is the fan vertex, and the */
+ /* destination of fixuptri is the fan vertex. */
+ oprevself(fixuptri);
+ }
+ /* Check for two intersecting segments. */
+ tspivot(fixuptri, crosssubseg);
+ if (crosssubseg.ss == m->dummysub) {
+ flip(m, b, &fixuptri); /* May create inverted triangle at left. */
+ }
+ else {
+ /* We've collided with a segment between endpoint1 and endpoint2. */
+ collision = 1;
+ /* Insert a vertex at the intersection. */
+ segmentintersection(m, b, &fixuptri, &crosssubseg, endpoint2);
+ done = 1;
+ }
+ }
+ }
+ } while (!done);
+ /* Insert a subsegment to make the segment permanent. */
+ insertsubseg(m, b, &fixuptri, newmark);
+ /* If there was a collision with an interceding vertex, install another */
+ /* segment connecting that vertex with endpoint2. */
+ if (collision) {
+ /* Insert the remainder of the segment. */
+ if (!scoutsegment(m, b, &fixuptri, endpoint2, newmark)) {
+ constrainededge(m, b, &fixuptri, endpoint2, newmark);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* insertsegment() Insert a PSLG segment into a triangulation. */
+/* */
+/*****************************************************************************/
+
+void insertsegment(struct mesh *m, struct behavior *b, vertex endpoint1, vertex endpoint2,
+ int newmark) {
+ struct otri searchtri1, searchtri2;
+ triangle encodedtri;
+ vertex checkvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (b->verbose > 1) {
+ printf( " Connecting (%.12g, %.12g) to (%.12g, %.12g).\n",
+ endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]);
+ }
+
+ /* Find a triangle whose origin is the segment's first endpoint. */
+ checkvertex = (vertex) NULL;
+ encodedtri = vertex2tri(endpoint1);
+ if (encodedtri != (triangle) NULL) {
+ decode(encodedtri, searchtri1);
+ org(searchtri1, checkvertex);
+ }
+ if (checkvertex != endpoint1) {
+ /* Find a boundary triangle to search from. */
+ searchtri1.tri = m->dummytri;
+ searchtri1.orient = 0;
+ symself(searchtri1);
+ /* Search for the segment's first endpoint by point location. */
+ if (locate(m, b, endpoint1, &searchtri1) != ONVERTEX) {
+ printf( "Internal error in insertsegment(): Unable to locate PSLG vertex\n");
+ printf(" (%.12g, %.12g) in triangulation.\n", endpoint1[0], endpoint1[1]);
+ internalerror();
+ }
+ }
+ /* Remember this triangle to improve subsequent point location. */
+ otricopy(searchtri1, m->recenttri);
+ /* Scout the beginnings of a path from the first endpoint */
+ /* toward the second. */
+ if (scoutsegment(m, b, &searchtri1, endpoint2, newmark)) {
+ /* The segment was easily inserted. */
+ return;
+ }
+ /* The first endpoint may have changed if a collision with an intervening */
+ /* vertex on the segment occurred. */
+ org(searchtri1, endpoint1);
+
+ /* Find a triangle whose origin is the segment's second endpoint. */
+ checkvertex = (vertex) NULL;
+ encodedtri = vertex2tri(endpoint2);
+ if (encodedtri != (triangle) NULL) {
+ decode(encodedtri, searchtri2);
+ org(searchtri2, checkvertex);
+ }
+ if (checkvertex != endpoint2) {
+ /* Find a boundary triangle to search from. */
+ searchtri2.tri = m->dummytri;
+ searchtri2.orient = 0;
+ symself(searchtri2);
+ /* Search for the segment's second endpoint by point location. */
+ if (locate(m, b, endpoint2, &searchtri2) != ONVERTEX) {
+ printf( "Internal error in insertsegment(): Unable to locate PSLG vertex\n");
+ printf(" (%.12g, %.12g) in triangulation.\n", endpoint2[0], endpoint2[1]);
+ internalerror();
+ }
+ }
+ /* Remember this triangle to improve subsequent point location. */
+ otricopy(searchtri2, m->recenttri);
+ /* Scout the beginnings of a path from the second endpoint */
+ /* toward the first. */
+ if (scoutsegment(m, b, &searchtri2, endpoint1, newmark)) {
+ /* The segment was easily inserted. */
+ return;
+ }
+ /* The second endpoint may have changed if a collision with an intervening */
+ /* vertex on the segment occurred. */
+ org(searchtri2, endpoint2);
+
+#ifndef REDUCED
+#ifndef CDT_ONLY
+ if (b->splitseg)
+ {
+ /* Insert vertices to force the segment into the triangulation. */
+ conformingedge(m, b, endpoint1, endpoint2, newmark);
+ }
+ else
+ {
+#endif /* not CDT_ONLY */
+#endif /* not REDUCED */
+ /* Insert the segment directly into the triangulation. */
+ constrainededge(m, b, &searchtri1, endpoint2, newmark);
+#ifndef REDUCED
+#ifndef CDT_ONLY
+}
+#endif /* not CDT_ONLY */
+#endif /* not REDUCED */
+}
+
+/*****************************************************************************/
+/* */
+/* markhull() Cover the convex hull of a triangulation with subsegments. */
+/* */
+/*****************************************************************************/
+
+void markhull(struct mesh *m, struct behavior *b) {
+ struct otri hulltri;
+ struct otri nexttri;
+ struct otri starttri;
+ triangle ptr; /* Temporary variable used by sym() and oprev(). */
+
+ /* Find a triangle handle on the hull. */
+ hulltri.tri = m->dummytri;
+ hulltri.orient = 0;
+ symself(hulltri);
+ /* Remember where we started so we know when to stop. */
+ otricopy(hulltri, starttri);
+ /* Go once counterclockwise around the convex hull. */
+ do {
+ /* Create a subsegment if there isn't already one here. */
+ insertsubseg(m, b, &hulltri, 1);
+ /* To find the next hull edge, go clockwise around the next vertex. */
+ lnextself(hulltri);
+ oprev(hulltri, nexttri);
+ while (nexttri.tri != m->dummytri) {
+ otricopy(nexttri, hulltri);
+ oprev(hulltri, nexttri);
+ }
+ } while (!otriequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/* */
+/* formskeleton() Create the segments of a triangulation, including PSLG */
+/* segments and edges on the convex hull. */
+/* */
+/* The PSLG segments are read from a .poly file. The return value is the */
+/* number of segments in the file. */
+/* */
+/*****************************************************************************/
+
+void formskeleton(struct mesh *m, struct behavior *b, int *segmentlist, int *segmentmarkerlist,
+ int numberofsegments) {
+ char polyfilename[6];
+ int index;
+ vertex endpoint1, endpoint2;
+ int segmentmarkers;
+ int end1, end2;
+ int boundmarker;
+ int i;
+
+ if (b->poly) {
+ if (!b->quiet) {
+ printf("Recovering segments in Delaunay triangulation.\n");
+ }
+ strcpy(polyfilename, "input");
+ m->insegments = numberofsegments;
+ segmentmarkers = segmentmarkerlist != (int *) NULL;
+ index = 0;
+ /* If the input vertices are collinear, there is no triangulation, */
+ /* so don't try to insert segments. */
+ if (m->triangles.items == 0) {
+ return;
+ }
+
+ /* If segments are to be inserted, compute a mapping */
+ /* from vertices to triangles. */
+ if (m->insegments > 0) {
+ makevertexmap(m, b);
+ if (b->verbose) {
+ printf(" Recovering PSLG segments.\n");
+ }
+ }
+
+ boundmarker = 0;
+ /* Read and insert the segments. */
+ for (i = 0; i < m->insegments; i++) {
+ end1 = segmentlist[index++];
+ end2 = segmentlist[index++];
+ if (segmentmarkers) {
+ boundmarker = segmentmarkerlist[i];
+ }
+ if ((end1 < b->firstnumber) || (end1 >= b->firstnumber + m->invertices)) {
+ if (!b->quiet) {
+ printf( "Warning: Invalid first endpoint of segment %d in %s.\n",
+ b->firstnumber + i, polyfilename);
+ }
+ }
+ else if ((end2 < b->firstnumber) || (end2 >= b->firstnumber + m->invertices)) {
+ if (!b->quiet) {
+ printf( "Warning: Invalid second endpoint of segment %d in %s.\n",
+ b->firstnumber + i, polyfilename);
+ }
+ }
+ else {
+ /* Find the vertices numbered `end1' and `end2'. */
+ endpoint1 = getvertex(m, b, end1);
+ endpoint2 = getvertex(m, b, end2);
+ if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) {
+ if (!b->quiet) {
+ printf( "Warning: Endpoints of segment %d are coincident in %s.\n",
+ b->firstnumber + i, polyfilename);
+ }
+ }
+ else {
+ insertsegment(m, b, endpoint1, endpoint2, boundmarker);
+ }
+ }
+ }
+ }
+ else {
+ m->insegments = 0;
+ }
+ if (b->convex || !b->poly) {
+ /* Enclose the convex hull with subsegments. */
+ if (b->verbose) {
+ printf(" Enclosing convex hull with segments.\n");
+ }
+ markhull(m, b);
+ }
+}
+
+/** **/
+/** **/
+/********* Segment insertion ends here *********/
+
+/********* Carving out holes and concavities begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* infecthull() Virally infect all of the triangles of the convex hull */
+/* that are not protected by subsegments. Where there are */
+/* subsegments, set boundary markers as appropriate. */
+/* */
+/*****************************************************************************/
+
+void infecthull(struct mesh *m, struct behavior *b) {
+ struct otri hulltri;
+ struct otri nexttri;
+ struct otri starttri;
+ struct osub hullsubseg;
+ triangle **deadtriangle;
+ vertex horg, hdest;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose) {
+ printf(" Marking concavities (external triangles) for elimination.\n");
+ }
+ /* Find a triangle handle on the hull. */
+ hulltri.tri = m->dummytri;
+ hulltri.orient = 0;
+ symself(hulltri);
+ /* Remember where we started so we know when to stop. */
+ otricopy(hulltri, starttri);
+ /* Go once counterclockwise around the convex hull. */
+ do {
+ /* Ignore triangles that are already infected. */
+ if (!infected(hulltri)) {
+ /* Is the triangle protected by a subsegment? */
+ tspivot(hulltri, hullsubseg);
+ if (hullsubseg.ss == m->dummysub) {
+ /* The triangle is not protected; infect it. */
+ if (!infected(hulltri)) {
+ infect(hulltri);
+ deadtriangle = (triangle **) poolalloc(&m->viri);
+ *deadtriangle = hulltri.tri;
+ }
+ }
+ else {
+ /* The triangle is protected; set boundary markers if appropriate. */
+ if (mark(hullsubseg) == 0) {
+ setmark(hullsubseg, 1);
+ org(hulltri, horg);
+ dest(hulltri, hdest);
+ if (vertexmark(horg) == 0) {
+ setvertexmark(horg, 1);
+ }
+ if (vertexmark(hdest) == 0) {
+ setvertexmark(hdest, 1);
+ }
+ }
+ }
+ }
+ /* To find the next hull edge, go clockwise around the next vertex. */
+ lnextself(hulltri);
+ oprev(hulltri, nexttri);
+ while (nexttri.tri != m->dummytri) {
+ otricopy(nexttri, hulltri);
+ oprev(hulltri, nexttri);
+ }
+ } while (!otriequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/* */
+/* plague() Spread the virus from all infected triangles to any neighbors */
+/* not protected by subsegments. Delete all infected triangles. */
+/* */
+/* This is the procedure that actually creates holes and concavities. */
+/* */
+/* This procedure operates in two phases. The first phase identifies all */
+/* the triangles that will die, and marks them as infected. They are */
+/* marked to ensure that each triangle is added to the virus pool only */
+/* once, so the procedure will terminate. */
+/* */
+/* The second phase actually eliminates the infected triangles. It also */
+/* eliminates orphaned vertices. */
+/* */
+/*****************************************************************************/
+
+void plague(struct mesh *m, struct behavior *b) {
+ struct otri testtri;
+ struct otri neighbor;
+ triangle **virusloop;
+ triangle **deadtriangle;
+ struct osub neighborsubseg;
+ vertex testvertex;
+ vertex norg, ndest;
+ vertex deadorg, deaddest, deadapex;
+ int killorg;
+ triangle ptr; /* Temporary variable used by sym() and onext(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose) {
+ printf(" Marking neighbors of marked triangles.\n");
+ }
+ /* Loop through all the infected triangles, spreading the virus to */
+ /* their neighbors, then to their neighbors' neighbors. */
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+ /* A triangle is marked as infected by messing with one of its pointers */
+ /* to subsegments, setting it to an illegal value. Hence, we have to */
+ /* temporarily uninfect this triangle so that we can examine its */
+ /* adjacent subsegments. */
+ uninfect(testtri);
+ if (b->verbose > 2) {
+ /* Assign the triangle an orientation for convenience in */
+ /* checking its vertices. */
+ testtri.orient = 0;
+ org(testtri, deadorg);
+ dest(testtri, deaddest);
+ apex(testtri, deadapex);
+ printf(
+ " Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", deadorg[0], deadorg[1], deaddest[0], deaddest[1], deadapex[0], deadapex[1]);
+ }
+ /* Check each of the triangle's three neighbors. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ /* Find the neighbor. */
+ sym(testtri, neighbor);
+ /* Check for a subsegment between the triangle and its neighbor. */
+ tspivot(testtri, neighborsubseg);
+ /* Check if the neighbor is nonexistent or already infected. */
+ if ((neighbor.tri == m->dummytri) || infected(neighbor)) {
+ if (neighborsubseg.ss != m->dummysub) {
+ /* There is a subsegment separating the triangle from its */
+ /* neighbor, but both triangles are dying, so the subsegment */
+ /* dies too. */
+ subsegdealloc(m, neighborsubseg.ss);
+ if (neighbor.tri != m->dummytri) {
+ /* Make sure the subsegment doesn't get deallocated again */
+ /* later when the infected neighbor is visited. */
+ uninfect(neighbor);
+ tsdissolve(neighbor);
+ infect(neighbor);
+ }
+ }
+ }
+ else { /* The neighbor exists and is not infected. */
+ if (neighborsubseg.ss == m->dummysub) {
+ /* There is no subsegment protecting the neighbor, so */
+ /* the neighbor becomes infected. */
+ if (b->verbose > 2) {
+ org(neighbor, deadorg);
+ dest(neighbor, deaddest);
+ apex(neighbor, deadapex);
+ printf(
+ " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", deadorg[0], deadorg[1], deaddest[0], deaddest[1], deadapex[0], deadapex[1]);
+ }
+ infect(neighbor);
+ /* Ensure that the neighbor's neighbors will be infected. */
+ deadtriangle = (triangle **) poolalloc(&m->viri);
+ *deadtriangle = neighbor.tri;
+ }
+ else { /* The neighbor is protected by a subsegment. */
+ /* Remove this triangle from the subsegment. */
+ stdissolve(neighborsubseg);
+ /* The subsegment becomes a boundary. Set markers accordingly. */
+ if (mark(neighborsubseg) == 0) {
+ setmark(neighborsubseg, 1);
+ }
+ org(neighbor, norg);
+ dest(neighbor, ndest);
+ if (vertexmark(norg) == 0) {
+ setvertexmark(norg, 1);
+ }
+ if (vertexmark(ndest) == 0) {
+ setvertexmark(ndest, 1);
+ }
+ }
+ }
+ }
+ /* Remark the triangle as infected, so it doesn't get added to the */
+ /* virus pool again. */
+ infect(testtri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+
+ if (b->verbose) {
+ printf(" Deleting marked triangles.\n");
+ }
+
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+
+ /* Check each of the three corners of the triangle for elimination. */
+ /* This is done by walking around each vertex, checking if it is */
+ /* still connected to at least one live triangle. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ org(testtri, testvertex);
+ /* Check if the vertex has already been tested. */
+ if (testvertex != (vertex) NULL) {
+ killorg = 1;
+ /* Mark the corner of the triangle as having been tested. */
+ setorg(testtri, NULL);
+ /* Walk counterclockwise about the vertex. */
+ onext(testtri, neighbor);
+ /* Stop upon reaching a boundary or the starting triangle. */
+ while ((neighbor.tri != m->dummytri) && (!otriequal(neighbor, testtri))) {
+ if (infected(neighbor)) {
+ /* Mark the corner of this triangle as having been tested. */
+ setorg(neighbor, NULL);
+ }
+ else {
+ /* A live triangle. The vertex survives. */
+ killorg = 0;
+ }
+ /* Walk counterclockwise about the vertex. */
+ onextself(neighbor);
+ }
+ /* If we reached a boundary, we must walk clockwise as well. */
+ if (neighbor.tri == m->dummytri) {
+ /* Walk clockwise about the vertex. */
+ oprev(testtri, neighbor);
+ /* Stop upon reaching a boundary. */
+ while (neighbor.tri != m->dummytri) {
+ if (infected(neighbor)) {
+ /* Mark the corner of this triangle as having been tested. */
+ setorg(neighbor, NULL);
+ }
+ else {
+ /* A live triangle. The vertex survives. */
+ killorg = 0;
+ }
+ /* Walk clockwise about the vertex. */
+ oprevself(neighbor);
+ }
+ }
+ if (killorg) {
+ if (b->verbose > 1) {
+ printf(" Deleting vertex (%.12g, %.12g)\n", testvertex[0], testvertex[1]);
+ }
+ setvertextype(testvertex, UNDEADVERTEX);
+ m->undeads++;
+ }
+ }
+ }
+
+ /* Record changes in the number of boundary edges, and disconnect */
+ /* dead triangles from their neighbors. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ sym(testtri, neighbor);
+ if (neighbor.tri == m->dummytri) {
+ /* There is no neighboring triangle on this edge, so this edge */
+ /* is a boundary edge. This triangle is being deleted, so this */
+ /* boundary edge is deleted. */
+ m->hullsize--;
+ }
+ else {
+ /* Disconnect the triangle from its neighbor. */
+ dissolve(neighbor);
+ /* There is a neighboring triangle on this edge, so this edge */
+ /* becomes a boundary edge when this triangle is deleted. */
+ m->hullsize++;
+ }
+ }
+ /* Return the dead triangle to the pool of triangles. */
+ triangledealloc(m, testtri.tri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+ /* Empty the virus pool. */
+ poolrestart(&m->viri);
+}
+
+/*****************************************************************************/
+/* */
+/* regionplague() Spread regional attributes and/or area constraints */
+/* (from a .poly file) throughout the mesh. */
+/* */
+/* This procedure operates in two phases. The first phase spreads an */
+/* attribute and/or an area constraint through a (segment-bounded) region. */
+/* The triangles are marked to ensure that each triangle is added to the */
+/* virus pool only once, so the procedure will terminate. */
+/* */
+/* The second phase uninfects all infected triangles, returning them to */
+/* normal. */
+/* */
+/*****************************************************************************/
+
+void regionplague(struct mesh *m, struct behavior *b, REAL attribute, REAL area) {
+ struct otri testtri;
+ struct otri neighbor;
+ triangle **virusloop;
+ triangle **regiontri;
+ struct osub neighborsubseg;
+ vertex regionorg, regiondest, regionapex;
+ triangle ptr; /* Temporary variable used by sym() and onext(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose > 1) {
+ printf(" Marking neighbors of marked triangles.\n");
+ }
+ /* Loop through all the infected triangles, spreading the attribute */
+ /* and/or area constraint to their neighbors, then to their neighbors' */
+ /* neighbors. */
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+ /* A triangle is marked as infected by messing with one of its pointers */
+ /* to subsegments, setting it to an illegal value. Hence, we have to */
+ /* temporarily uninfect this triangle so that we can examine its */
+ /* adjacent subsegments. */
+ uninfect(testtri);
+ if (b->regionattrib) {
+ /* Set an attribute. */
+ setelemattribute(testtri, m->eextras, attribute);
+ }
+ if (b->vararea) {
+ /* Set an area constraint. */
+ setareabound(testtri, area);
+ }
+ if (b->verbose > 2) {
+ /* Assign the triangle an orientation for convenience in */
+ /* checking its vertices. */
+ testtri.orient = 0;
+ org(testtri, regionorg);
+ dest(testtri, regiondest);
+ apex(testtri, regionapex);
+ printf( " Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+ regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+ regionapex[0], regionapex[1]);
+ }
+ /* Check each of the triangle's three neighbors. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ /* Find the neighbor. */
+ sym(testtri, neighbor);
+ /* Check for a subsegment between the triangle and its neighbor. */
+ tspivot(testtri, neighborsubseg);
+ /* Make sure the neighbor exists, is not already infected, and */
+ /* isn't protected by a subsegment. */
+ if ((neighbor.tri != m->dummytri) && !infected(neighbor)
+ && (neighborsubseg.ss == m->dummysub)) {
+ if (b->verbose > 2) {
+ org(neighbor, regionorg);
+ dest(neighbor, regiondest);
+ apex(neighbor, regionapex);
+ printf( " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+ regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+ regionapex[0], regionapex[1]);
+ }
+ /* Infect the neighbor. */
+ infect(neighbor);
+ /* Ensure that the neighbor's neighbors will be infected. */
+ regiontri = (triangle **) poolalloc(&m->viri);
+ *regiontri = neighbor.tri;
+ }
+ }
+ /* Remark the triangle as infected, so it doesn't get added to the */
+ /* virus pool again. */
+ infect(testtri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+
+ /* Uninfect all triangles. */
+ if (b->verbose > 1) {
+ printf(" Unmarking marked triangles.\n");
+ }
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+ uninfect(testtri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+ /* Empty the virus pool. */
+ poolrestart(&m->viri);
+}
+
+/*****************************************************************************/
+/* */
+/* carveholes() Find the holes and infect them. Find the area */
+/* constraints and infect them. Infect the convex hull. */
+/* Spread the infection and kill triangles. Spread the */
+/* area constraints. */
+/* */
+/* This routine mainly calls other routines to carry out all these */
+/* functions. */
+/* */
+/*****************************************************************************/
+
+void carveholes(struct mesh *m, struct behavior *b, REAL *holelist, int holes, REAL *regionlist,
+ int regions) {
+ struct otri searchtri;
+ struct otri triangleloop;
+ struct otri *regiontris;
+ triangle **holetri;
+ triangle **regiontri;
+ vertex searchorg, searchdest;
+ enum locateresult intersect;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (!(b->quiet || (b->noholes && b->convex))) {
+ printf("Removing unwanted triangles.\n");
+ if (b->verbose && (holes > 0)) {
+ printf(" Marking holes for elimination.\n");
+ }
+ }
+
+ if (regions > 0) {
+ /* Allocate storage for the triangles in which region points fall. */
+ regiontris = (struct otri *) trimalloc(regions * (int) sizeof(struct otri));
+ }
+ else {
+ regiontris = (struct otri *) NULL;
+ }
+
+ if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) {
+ /* Initialize a pool of viri to be used for holes, concavities, */
+ /* regional attributes, and/or regional area constraints. */
+ poolinit(&m->viri, sizeof(triangle *), VIRUSPERBLOCK, VIRUSPERBLOCK, 0);
+ }
+
+ if (!b->convex) {
+ /* Mark as infected any unprotected triangles on the boundary. */
+ /* This is one way by which concavities are created. */
+ infecthull(m, b);
+ }
+
+ if ((holes > 0) && !b->noholes) {
+ /* Infect each triangle in which a hole lies. */
+ for (i = 0; i < 2 * holes; i += 2) {
+ /* Ignore holes that aren't within the bounds of the mesh. */
+ if ((holelist[i] >= m->xmin) && (holelist[i] <= m->xmax) && (holelist[i + 1] >= m->ymin)
+ && (holelist[i + 1] <= m->ymax)) {
+ /* Start searching from some triangle on the outer boundary. */
+ searchtri.tri = m->dummytri;
+ searchtri.orient = 0;
+ symself(searchtri);
+ /* Ensure that the hole is to the left of this boundary edge; */
+ /* otherwise, locate() will falsely report that the hole */
+ /* falls within the starting triangle. */
+ org(searchtri, searchorg);
+ dest(searchtri, searchdest);
+ if (counterclockwise(m, b, searchorg, searchdest, &holelist[i]) > 0.0) {
+ /* Find a triangle that contains the hole. */
+ intersect = locate(m, b, &holelist[i], &searchtri);
+ if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+ /* Infect the triangle. This is done by marking the triangle */
+ /* as infected and including the triangle in the virus pool. */
+ infect(searchtri);
+ holetri = (triangle **) poolalloc(&m->viri);
+ *holetri = searchtri.tri;
+ }
+ }
+ }
+ }
+ }
+
+ /* Now, we have to find all the regions BEFORE we carve the holes, because */
+ /* locate() won't work when the triangulation is no longer convex. */
+ /* (Incidentally, this is the reason why regional attributes and area */
+ /* constraints can't be used when refining a preexisting mesh, which */
+ /* might not be convex; they can only be used with a freshly */
+ /* triangulated PSLG.) */
+ if (regions > 0) {
+ /* Find the starting triangle for each region. */
+ for (i = 0; i < regions; i++) {
+ regiontris[i].tri = m->dummytri;
+ /* Ignore region points that aren't within the bounds of the mesh. */
+ if ((regionlist[4 * i] >= m->xmin) && (regionlist[4 * i] <= m->xmax)
+ && (regionlist[4 * i + 1] >= m->ymin) && (regionlist[4 * i + 1] <= m->ymax)) {
+ /* Start searching from some triangle on the outer boundary. */
+ searchtri.tri = m->dummytri;
+ searchtri.orient = 0;
+ symself(searchtri);
+ /* Ensure that the region point is to the left of this boundary */
+ /* edge; otherwise, locate() will falsely report that the */
+ /* region point falls within the starting triangle. */
+ org(searchtri, searchorg);
+ dest(searchtri, searchdest);
+ if (counterclockwise(m, b, searchorg, searchdest, ®ionlist[4 * i]) > 0.0) {
+ /* Find a triangle that contains the region point. */
+ intersect = locate(m, b, ®ionlist[4 * i], &searchtri);
+ if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+ /* Record the triangle for processing after the */
+ /* holes have been carved. */
+ otricopy(searchtri, regiontris[i]);
+ }
+ }
+ }
+ }
+ }
+
+ if (m->viri.items > 0) {
+ /* Carve the holes and concavities. */
+ plague(m, b);
+ }
+ /* The virus pool should be empty now. */
+
+ if (regions > 0) {
+ if (!b->quiet) {
+ if (b->regionattrib) {
+ if (b->vararea) {
+ printf("Spreading regional attributes and area constraints.\n");
+ }
+ else {
+ printf("Spreading regional attributes.\n");
+ }
+ }
+ else {
+ printf("Spreading regional area constraints.\n");
+ }
+ }
+ if (b->regionattrib && !b->refine) {
+ /* Assign every triangle a regional attribute of zero. */
+ traversalinit(&m->triangles);
+ triangleloop.orient = 0;
+ triangleloop.tri = triangletraverse(m);
+ while (triangleloop.tri != (triangle *) NULL) {
+ setelemattribute(triangleloop, m->eextras, 0.0);
+ triangleloop.tri = triangletraverse(m);
+ }
+ }
+ for (i = 0; i < regions; i++) {
+ if (regiontris[i].tri != m->dummytri) {
+ /* Make sure the triangle under consideration still exists. */
+ /* It may have been eaten by the virus. */
+ if (!deadtri(regiontris[i].tri)) {
+ /* Put one triangle in the virus pool. */
+ infect(regiontris[i]);
+ regiontri = (triangle **) poolalloc(&m->viri);
+ *regiontri = regiontris[i].tri;
+ /* Apply one region's attribute and/or area constraint. */
+ regionplague(m, b, regionlist[4 * i + 2], regionlist[4 * i + 3]);
+ /* The virus pool should be empty now. */
+ }
+ }
+ }
+ if (b->regionattrib && !b->refine) {
+ /* Note the fact that each triangle has an additional attribute. */
+ m->eextras++;
+ }
+ }
+
+ /* Free up memory. */
+ if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) {
+ pooldeinit(&m->viri);
+ }
+ if (regions > 0) {
+ trifree((VOID *) regiontris);
+ }
+}
+
+/** **/
+/** **/
+/********* Carving out holes and concavities ends here *********/
+
+/*****************************************************************************/
+/* */
+/* highorder() Create extra nodes for quadratic subparametric elements. */
+/* */
+/*****************************************************************************/
+
+void highorder(struct mesh *m, struct behavior *b) {
+ struct otri triangleloop, trisym;
+ struct osub checkmark;
+ vertex newvertex;
+ vertex torg, tdest;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (!b->quiet) {
+ printf("Adding vertices for second-order triangles.\n");
+ }
+ /* The following line ensures that dead items in the pool of nodes */
+ /* cannot be allocated for the extra nodes associated with high */
+ /* order elements. This ensures that the primary nodes (at the */
+ /* corners of elements) will occur earlier in the output files, and */
+ /* have lower indices, than the extra nodes. */
+ m->vertices.deaditemstack = (VOID *) NULL;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ /* To loop over the set of edges, loop over all triangles, and look at */
+ /* the three edges of each triangle. If there isn't another triangle */
+ /* adjacent to the edge, operate on the edge. If there is another */
+ /* adjacent triangle, operate on the edge only if the current triangle */
+ /* has a smaller pointer than its neighbor. This way, each edge is */
+ /* considered only once. */
+ while (triangleloop.tri != (triangle *) NULL) {
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ sym(triangleloop, trisym);
+ if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+ org(triangleloop, torg);
+ dest(triangleloop, tdest);
+ /* Create a new node in the middle of the edge. Interpolate */
+ /* its attributes. */
+ newvertex = (vertex) poolalloc(&m->vertices);
+ for (i = 0; i < 2 + m->nextras; i++) {
+ newvertex[i] = 0.5 * (torg[i] + tdest[i]);
+ }
+ /* Set the new node's marker to zero or one, depending on */
+ /* whether it lies on a boundary. */
+ setvertexmark(newvertex, trisym.tri == m->dummytri);
+ setvertextype(newvertex, trisym.tri == m->dummytri ? FREEVERTEX : SEGMENTVERTEX);
+ if (b->usesegments) {
+ tspivot(triangleloop, checkmark);
+ /* If this edge is a segment, transfer the marker to the new node. */
+ if (checkmark.ss != m->dummysub) {
+ setvertexmark(newvertex, mark(checkmark));
+ setvertextype(newvertex, SEGMENTVERTEX);
+ }
+ }
+ if (b->verbose > 1) {
+ printf(" Creating (%.12g, %.12g).\n", newvertex[0], newvertex[1]);
+ }
+ /* Record the new node in the (one or two) adjacent elements. */
+ triangleloop.tri[m->highorderindex + triangleloop.orient] = (triangle) newvertex;
+ if (trisym.tri != m->dummytri) {
+ trisym.tri[m->highorderindex + trisym.orient] = (triangle) newvertex;
+ }
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* transfernodes() Read the vertices from memory. */
+/* */
+/*****************************************************************************/
+
+void transfernodes(struct mesh *m, struct behavior *b, REAL *pointlist, REAL *pointattriblist,
+ int *pointmarkerlist, int numberofpoints, int numberofpointattribs) {
+ vertex vertexloop;
+ REAL x, y;
+ int i, j;
+ int coordindex;
+ int attribindex;
+
+ m->invertices = numberofpoints;
+ m->mesh_dim = 2;
+ m->nextras = numberofpointattribs;
+ m->readnodefile = 0;
+ if (m->invertices < 3) {
+ printf("Error: Input must have at least three input vertices.\n");
+ triexit(1);
+ }
+ if (m->nextras == 0) {
+ b->weighted = 0;
+ }
+
+ initializevertexpool(m, b);
+
+ /* Read the vertices. */
+ coordindex = 0;
+ attribindex = 0;
+ for (i = 0; i < m->invertices; i++) {
+ vertexloop = (vertex) poolalloc(&m->vertices);
+ /* Read the vertex coordinates. */
+ x = vertexloop[0] = pointlist[coordindex++];
+ y = vertexloop[1] = pointlist[coordindex++];
+ /* Read the vertex attributes. */
+ for (j = 0; j < numberofpointattribs; j++) {
+ vertexloop[2 + j] = pointattriblist[attribindex++];
+ }
+ if (pointmarkerlist != (int *) NULL) {
+ /* Read a vertex marker. */
+ setvertexmark(vertexloop, pointmarkerlist[i]);
+ }
+ else {
+ /* If no markers are specified, they default to zero. */
+ setvertexmark(vertexloop, 0);
+ }
+
+ // ----------------------------------------------
+ for (j = (i - 1) * 2; j >= 0; j -= 2){
+ if (x == pointlist[j] && y == pointlist[j+1]){
+ printf("skip duplicate %d\n", j >> 1);
+ setvertextype(vertexloop, UNDEADVERTEX);
+ vertexloop[0] = 0xffffffff;
+ vertexloop[1] = 0xffffffff;
+ break;
+ }
+ }
+ if (j >= 0)
+ continue;
+ // ----------------------------------------------
+
+ setvertextype(vertexloop, INPUTVERTEX);
+ /* Determine the smallest and largest x and y coordinates. */
+ if (i == 0) {
+ m->xmin = m->xmax = x;
+ m->ymin = m->ymax = y;
+ }
+ else {
+ m->xmin = (x < m->xmin) ? x : m->xmin;
+ m->xmax = (x > m->xmax) ? x : m->xmax;
+ m->ymin = (y < m->ymin) ? y : m->ymin;
+ m->ymax = (y > m->ymax) ? y : m->ymax;
+ }
+ }
+
+ /* Nonexistent x value used as a flag to mark circle events in sweepline */
+ /* Delaunay algorithm. */
+ m->xminextreme = 10 * m->xmin - 9 * m->xmax;
+}
+
+/*****************************************************************************/
+/* */
+/* writenodes() Number the vertices and write them to a .node file. */
+/* */
+/* To save memory, the vertex numbers are written over the boundary markers */
+/* after the vertices are written to a file. */
+/* */
+/*****************************************************************************/
+
+void writenodes(struct mesh *m, struct behavior *b, REAL **pointlist, REAL **pointattriblist,
+ int **pointmarkerlist) {
+ REAL *plist;
+ REAL *palist;
+ int *pmlist;
+ int coordindex;
+ int attribindex;
+ vertex vertexloop;
+ long outvertices;
+ int vertexnumber;
+ int i;
+
+ if (b->jettison) {
+ outvertices = m->vertices.items - m->undeads;
+ }
+ else {
+ outvertices = m->vertices.items;
+ }
+
+ if (!b->quiet) {
+ printf("Writing vertices.\n");
+ }
+ /* Allocate memory for output vertices if necessary. */
+ if (*pointlist == (REAL *) NULL) {
+ *pointlist = (REAL *) trimalloc((int) (outvertices * 2 * sizeof(REAL)));
+ }
+ /* Allocate memory for output vertex attributes if necessary. */
+ if ((m->nextras > 0) && (*pointattriblist == (REAL *) NULL)) {
+ *pointattriblist = (REAL *) trimalloc((int) (outvertices * m->nextras * sizeof(REAL)));
+ }
+ /* Allocate memory for output vertex markers if necessary. */
+ if (!b->nobound && (*pointmarkerlist == (int *) NULL)) {
+ *pointmarkerlist = (int *) trimalloc((int) (outvertices * sizeof(int)));
+ }
+ plist = *pointlist;
+ palist = *pointattriblist;
+ pmlist = *pointmarkerlist;
+ coordindex = 0;
+ attribindex = 0;
+
+ traversalinit(&m->vertices);
+ vertexnumber = b->firstnumber;
+ vertexloop = vertextraverse(m);
+ while (vertexloop != (vertex) NULL) {
+ if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) {
+ /* X and y coordinates. */
+ plist[coordindex++] = vertexloop[0];
+ plist[coordindex++] = vertexloop[1];
+ /* Vertex attributes. */
+ for (i = 0; i < m->nextras; i++) {
+ palist[attribindex++] = vertexloop[2 + i];
+ }
+ if (!b->nobound) {
+ /* Copy the boundary marker. */
+ pmlist[vertexnumber - b->firstnumber] = vertexmark(vertexloop);
+ }
+ setvertexmark(vertexloop, vertexnumber);
+ vertexnumber++;
+ }
+ vertexloop = vertextraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* numbernodes() Number the vertices. */
+/* */
+/* Each vertex is assigned a marker equal to its number. */
+/* */
+/* Used when writenodes() is not called because no .node file is written. */
+/* */
+/*****************************************************************************/
+
+void numbernodes(struct mesh *m, struct behavior *b) {
+ vertex vertexloop;
+ int vertexnumber;
+
+ traversalinit(&m->vertices);
+ vertexnumber = b->firstnumber;
+ vertexloop = vertextraverse(m);
+ while (vertexloop != (vertex) NULL) {
+ setvertexmark(vertexloop, vertexnumber);
+ if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) {
+ vertexnumber++;
+ }
+ vertexloop = vertextraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writeelements() Write the triangles to an .ele file. */
+/* */
+/*****************************************************************************/
+
+void writeelements(struct mesh *m, struct behavior *b, INDICE **trianglelist,
+ REAL **triangleattriblist) {
+ INDICE *tlist;
+ REAL *talist;
+ int vertexindex;
+ int attribindex;
+ struct otri triangleloop;
+ vertex p1, p2, p3;
+ vertex mid1, mid2, mid3;
+ long elementnumber;
+ int i;
+
+ if (!b->quiet) {
+ printf("Writing triangles.\n");
+ }
+ /* Allocate memory for output triangles if necessary. */
+ if (*trianglelist == (INDICE *) NULL) {
+ *trianglelist = (INDICE *) trimalloc(
+ (INDICE) (m->triangles.items * ((b->order + 1) * (b->order + 2) / 2) * sizeof(int)));
+ }
+ /* Allocate memory for output triangle attributes if necessary. */
+ if ((m->eextras > 0) && (*triangleattriblist == (REAL *) NULL)) {
+ *triangleattriblist = (REAL *) trimalloc(
+ (int) (m->triangles.items * m->eextras * sizeof(REAL)));
+ }
+ tlist = *trianglelist;
+ talist = *triangleattriblist;
+ vertexindex = 0;
+ attribindex = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ elementnumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ org(triangleloop, p1);
+ dest(triangleloop, p2);
+ apex(triangleloop, p3);
+ if (b->order == 1) {
+ tlist[vertexindex++] = vertexmark(p1);
+ tlist[vertexindex++] = vertexmark(p2);
+ tlist[vertexindex++] = vertexmark(p3);
+ }
+ else {
+ mid1 = (vertex) triangleloop.tri[m->highorderindex + 1];
+ mid2 = (vertex) triangleloop.tri[m->highorderindex + 2];
+ mid3 = (vertex) triangleloop.tri[m->highorderindex];
+ tlist[vertexindex++] = vertexmark(p1);
+ tlist[vertexindex++] = vertexmark(p2);
+ tlist[vertexindex++] = vertexmark(p3);
+ tlist[vertexindex++] = vertexmark(mid1);
+ tlist[vertexindex++] = vertexmark(mid2);
+ tlist[vertexindex++] = vertexmark(mid3);
+ }
+
+ for (i = 0; i < m->eextras; i++) {
+ talist[attribindex++] = elemattribute(triangleloop, i);
+ }
+
+ triangleloop.tri = triangletraverse(m);
+ elementnumber++;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writepoly() Write the segments and holes to a .poly file. */
+/* */
+/*****************************************************************************/
+
+void writepoly(struct mesh *m, struct behavior *b, int **segmentlist, int **segmentmarkerlist) {
+ int *slist;
+ int *smlist;
+ int index;
+ struct osub subsegloop;
+ vertex endpoint1, endpoint2;
+ long subsegnumber;
+
+ if (!b->quiet) {
+ printf("Writing segments.\n");
+ }
+ /* Allocate memory for output segments if necessary. */
+ if (*segmentlist == (int *) NULL) {
+ *segmentlist = (int *) trimalloc((int) (m->subsegs.items * 2 * sizeof(int)));
+ }
+ /* Allocate memory for output segment markers if necessary. */
+ if (!b->nobound && (*segmentmarkerlist == (int *) NULL)) {
+ *segmentmarkerlist = (int *) trimalloc((int) (m->subsegs.items * sizeof(int)));
+ }
+ slist = *segmentlist;
+ smlist = *segmentmarkerlist;
+ index = 0;
+
+ traversalinit(&m->subsegs);
+ subsegloop.ss = subsegtraverse(m);
+ subsegloop.ssorient = 0;
+ subsegnumber = b->firstnumber;
+ while (subsegloop.ss != (subseg *) NULL) {
+ sorg(subsegloop, endpoint1);
+ sdest(subsegloop, endpoint2);
+ /* Copy indices of the segment's two endpoints. */
+ slist[index++] = vertexmark(endpoint1);
+ slist[index++] = vertexmark(endpoint2);
+ if (!b->nobound) {
+ /* Copy the boundary marker. */
+ smlist[subsegnumber - b->firstnumber] = mark(subsegloop);
+ }
+
+ subsegloop.ss = subsegtraverse(m);
+ subsegnumber++;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writeedges() Write the edges to an .edge file. */
+/* */
+/*****************************************************************************/
+
+void writeedges(struct mesh *m, struct behavior *b, int **edgelist, int **edgemarkerlist) {
+ int *elist;
+ int *emlist;
+ int index;
+ struct otri triangleloop, trisym;
+ struct osub checkmark;
+ vertex p1, p2;
+ long edgenumber;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (!b->quiet) {
+ printf("Writing edges.\n");
+ }
+ /* Allocate memory for edges if necessary. */
+ if (*edgelist == (int *) NULL) {
+ *edgelist = (int *) trimalloc((int) (m->edges * 2 * sizeof(int)));
+ }
+ /* Allocate memory for edge markers if necessary. */
+ if (!b->nobound && (*edgemarkerlist == (int *) NULL)) {
+ *edgemarkerlist = (int *) trimalloc((int) (m->edges * sizeof(int)));
+ }
+ elist = *edgelist;
+ emlist = *edgemarkerlist;
+ index = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ edgenumber = b->firstnumber;
+ /* To loop over the set of edges, loop over all triangles, and look at */
+ /* the three edges of each triangle. If there isn't another triangle */
+ /* adjacent to the edge, operate on the edge. If there is another */
+ /* adjacent triangle, operate on the edge only if the current triangle */
+ /* has a smaller pointer than its neighbor. This way, each edge is */
+ /* considered only once. */
+ while (triangleloop.tri != (triangle *) NULL) {
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ sym(triangleloop, trisym);
+ if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+ org(triangleloop, p1);
+ dest(triangleloop, p2);
+ elist[index++] = vertexmark(p1);
+ elist[index++] = vertexmark(p2);
+ if (b->nobound) {
+ }
+ else {
+ /* Edge number, indices of two endpoints, and a boundary marker. */
+ /* If there's no subsegment, the boundary marker is zero. */
+ if (b->usesegments) {
+ tspivot(triangleloop, checkmark);
+ if (checkmark.ss == m->dummysub) {
+ emlist[edgenumber - b->firstnumber] = 0;
+ }
+ else {
+ emlist[edgenumber - b->firstnumber] = mark(checkmark);
+ }
+ }
+ else {
+ emlist[edgenumber - b->firstnumber] = trisym.tri == m->dummytri;
+ }
+ }
+ edgenumber++;
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writevoronoi() Write the Voronoi diagram to a .v.node and .v.edge */
+/* file. */
+/* */
+/* The Voronoi diagram is the geometric dual of the Delaunay triangulation. */
+/* Hence, the Voronoi vertices are listed by traversing the Delaunay */
+/* triangles, and the Voronoi edges are listed by traversing the Delaunay */
+/* edges. */
+/* */
+/* WARNING: In order to assign numbers to the Voronoi vertices, this */
+/* procedure messes up the subsegments or the extra nodes of every */
+/* element. Hence, you should call this procedure last. */
+/* */
+/*****************************************************************************/
+
+void writevoronoi(struct mesh *m, struct behavior *b, REAL **vpointlist, REAL **vpointattriblist,
+ int **vpointmarkerlist, int **vedgelist, int **vedgemarkerlist, REAL **vnormlist) {
+ REAL *plist;
+ REAL *palist;
+ int *elist;
+ REAL *normlist;
+ int coordindex;
+ int attribindex;
+ struct otri triangleloop, trisym;
+ vertex torg, tdest, tapex;
+ REAL circumcenter[2];
+ REAL xi, eta;
+ long vnodenumber, vedgenumber;
+ int p1, p2;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (!b->quiet) {
+ printf("Writing Voronoi vertices.\n");
+ }
+ /* Allocate memory for Voronoi vertices if necessary. */
+ if (*vpointlist == (REAL *) NULL) {
+ *vpointlist = (REAL *) trimalloc((int) (m->triangles.items * 2 * sizeof(REAL)));
+ }
+ /* Allocate memory for Voronoi vertex attributes if necessary. */
+ if (*vpointattriblist == (REAL *) NULL) {
+ *vpointattriblist = (REAL *) trimalloc(
+ (int) (m->triangles.items * m->nextras * sizeof(REAL)));
+ }
+ *vpointmarkerlist = (int *) NULL;
+ plist = *vpointlist;
+ palist = *vpointattriblist;
+ coordindex = 0;
+ attribindex = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ vnodenumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ org(triangleloop, torg);
+ dest(triangleloop, tdest);
+ apex(triangleloop, tapex);
+ findcircumcenter(m, b, torg, tdest, tapex, circumcenter, &xi, &eta, 0);
+ /* X and y coordinates. */
+ plist[coordindex++] = circumcenter[0];
+ plist[coordindex++] = circumcenter[1];
+ for (i = 2; i < 2 + m->nextras; i++) {
+ /* Interpolate the vertex attributes at the circumcenter. */
+ palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i]) + eta * (tapex[i] - torg[i]);
+ }
+
+ *(int *) (triangleloop.tri + 6) = (int) vnodenumber;
+ triangleloop.tri = triangletraverse(m);
+ vnodenumber++;
+ }
+
+ if (!b->quiet) {
+ printf("Writing Voronoi edges.\n");
+ }
+ /* Allocate memory for output Voronoi edges if necessary. */
+ if (*vedgelist == (int *) NULL) {
+ *vedgelist = (int *) trimalloc((int) (m->edges * 2 * sizeof(int)));
+ }
+ *vedgemarkerlist = (int *) NULL;
+ /* Allocate memory for output Voronoi norms if necessary. */
+ if (*vnormlist == (REAL *) NULL) {
+ *vnormlist = (REAL *) trimalloc((int) (m->edges * 2 * sizeof(REAL)));
+ }
+ elist = *vedgelist;
+ normlist = *vnormlist;
+ coordindex = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ vedgenumber = b->firstnumber;
+ /* To loop over the set of edges, loop over all triangles, and look at */
+ /* the three edges of each triangle. If there isn't another triangle */
+ /* adjacent to the edge, operate on the edge. If there is another */
+ /* adjacent triangle, operate on the edge only if the current triangle */
+ /* has a smaller pointer than its neighbor. This way, each edge is */
+ /* considered only once. */
+ while (triangleloop.tri != (triangle *) NULL) {
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ sym(triangleloop, trisym);
+ if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+ /* Find the number of this triangle (and Voronoi vertex). */
+ p1 = *(int *) (triangleloop.tri + 6);
+ if (trisym.tri == m->dummytri) {
+ org(triangleloop, torg);
+ dest(triangleloop, tdest);
+ /* Copy an infinite ray. Index of one endpoint, and -1. */
+ elist[coordindex] = p1;
+ normlist[coordindex++] = tdest[1] - torg[1];
+ elist[coordindex] = -1;
+ normlist[coordindex++] = torg[0] - tdest[0];
+ }
+ else {
+ /* Find the number of the adjacent triangle (and Voronoi vertex). */
+ p2 = *(int *) (trisym.tri + 6);
+ /* Finite edge. Write indices of two endpoints. */
+ elist[coordindex] = p1;
+ normlist[coordindex++] = 0.0;
+ elist[coordindex] = p2;
+ normlist[coordindex++] = 0.0;
+ }
+ vedgenumber++;
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+void writeneighbors(struct mesh *m, struct behavior *b, int **neighborlist) {
+ int *nlist;
+ int index;
+ struct otri triangleloop, trisym;
+ long elementnumber;
+ int neighbor1, neighbor2, neighbor3;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (!b->quiet) {
+ printf("Writing neighbors.\n");
+ }
+ /* Allocate memory for neighbors if necessary. */
+ if (*neighborlist == (int *) NULL) {
+ *neighborlist = (int *) trimalloc((int) (m->triangles.items * 3 * sizeof(int)));
+ }
+ nlist = *neighborlist;
+ index = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ elementnumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ *(int *) (triangleloop.tri + 6) = (int) elementnumber;
+ triangleloop.tri = triangletraverse(m);
+ elementnumber++;
+ }
+ *(int *) (m->dummytri + 6) = -1;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ elementnumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ triangleloop.orient = 1;
+ sym(triangleloop, trisym);
+ neighbor1 = *(int *) (trisym.tri + 6);
+ triangleloop.orient = 2;
+ sym(triangleloop, trisym);
+ neighbor2 = *(int *) (trisym.tri + 6);
+ triangleloop.orient = 0;
+ sym(triangleloop, trisym);
+ neighbor3 = *(int *) (trisym.tri + 6);
+ nlist[index++] = neighbor1;
+ nlist[index++] = neighbor2;
+ nlist[index++] = neighbor3;
+
+ triangleloop.tri = triangletraverse(m);
+ elementnumber++;
+ }
+}
+
+/** **/
+/** **/
+/********* File I/O routines end here *********/
+
+/*****************************************************************************/
+/* */
+/* main() or triangulate() Gosh, do everything. */
+/* */
+/* The sequence is roughly as follows. Many of these steps can be skipped, */
+/* depending on the command line switches. */
+/* */
+/* - Initialize constants and parse the command line. */
+/* - Read the vertices from a file and either */
+/* - triangulate them (no -r), or */
+/* - read an old mesh from files and reconstruct it (-r). */
+/* - Insert the PSLG segments (-p), and possibly segments on the convex */
+/* hull (-c). */
+/* - Read the holes (-p), regional attributes (-pA), and regional area */
+/* constraints (-pa). Carve the holes and concavities, and spread the */
+/* regional attributes and area constraints. */
+/* - Enforce the constraints on minimum angle (-q) and maximum area (-a). */
+/* Also enforce the conforming Delaunay property (-q and -a). */
+/* - Compute the number of edges in the resulting mesh. */
+/* - Promote the mesh's linear triangles to higher order elements (-o). */
+/* - Write the output files and print the statistics. */
+/* - Check the consistency and Delaunay property of the mesh (-C). */
+/* */
+/*****************************************************************************/
+
+void triangulate(struct behavior *command, struct triangulateio *in, struct triangulateio *out,
+ struct triangulateio *vorout) {
+ struct mesh m;
+ struct behavior *b = command;
+ REAL *holearray; /* Array of holes. */
+ REAL *regionarray; /* Array of regional attributes and area constraints. */
+
+ triangleinit(&m);
+ //parsecommandline(1, &triswitches, &b);
+ m.steinerleft = b->steiner;
+
+ transfernodes(&m, b, in->pointlist, in->pointattributelist, in->pointmarkerlist,
+ in->numberofpoints, in->numberofpointattributes);
+
+#ifdef CDT_ONLY
+ m.hullsize = delaunay(&m, b); /* Triangulate the vertices. */
+#else /* not CDT_ONLY */
+ if (b->refine)
+ {
+ /* Read and reconstruct a mesh. */
+ m.hullsize = reconstruct(&m, b, in->trianglelist,
+ in->triangleattributelist, in->trianglearealist,
+ in->numberoftriangles, in->numberofcorners,
+ in->numberoftriangleattributes,
+ in->segmentlist, in->segmentmarkerlist,
+ in->numberofsegments);
+ }
+ else
+ {
+ m.hullsize = delaunay(&m, b); /* Triangulate the vertices. */
+ }
+#endif /* not CDT_ONLY */
+
+ /* Ensure that no vertex can be mistaken for a triangular bounding */
+ /* box vertex in insertvertex(). */
+ m.infvertex1 = (vertex) NULL;
+ m.infvertex2 = (vertex) NULL;
+ m.infvertex3 = (vertex) NULL;
+
+ if (b->usesegments) {
+ m.checksegments = 1; /* Segments will be introduced next. */
+ if (!b->refine) {
+ /* Insert PSLG segments and/or convex hull segments. */
+ formskeleton(&m, b, in->segmentlist, in->segmentmarkerlist, in->numberofsegments);
+ }
+ }
+
+ if (b->poly && (m.triangles.items > 0)) {
+ holearray = in->holelist;
+ m.holes = in->numberofholes;
+ regionarray = in->regionlist;
+ m.regions = in->numberofregions;
+ if (!b->refine) {
+ /* Carve out holes and concavities. */
+ carveholes(&m, b, holearray, m.holes, regionarray, m.regions);
+ }
+ }
+ else {
+ /* Without a PSLG, there can be no holes or regional attributes */
+ /* or area constraints. The following are set to zero to avoid */
+ /* an accidental free() later. */
+ m.holes = 0;
+ m.regions = 0;
+ }
+
+#ifndef CDT_ONLY
+ if (b->quality && (m.triangles.items > 0))
+ {
+ enforcequality(&m, b); /* Enforce angle and area constraints. */
+ }
+#endif /* not CDT_ONLY */
+
+#ifndef CDT_ONLY
+ if (b->quality)
+ {
+ printf("Quality milliseconds: %ld\n",
+ 1000l * (tv5.tv_sec - tv4.tv_sec) +
+ (tv5.tv_usec - tv4.tv_usec) / 1000l);
+ }
+#endif /* not CDT_ONLY */
+
+ /* Calculate the number of edges. */
+ m.edges = (3l * m.triangles.items + m.hullsize) / 2l;
+
+ if (b->order > 1) {
+ highorder(&m, b); /* Promote elements to higher polynomial order. */
+ }
+ if (!b->quiet) {
+ printf("\n");
+ }
+
+ if (b->jettison) {
+ out->numberofpoints = m.vertices.items - m.undeads;
+ }
+ else {
+ out->numberofpoints = m.vertices.items;
+ }
+ out->numberofpointattributes = m.nextras;
+ out->numberoftriangles = m.triangles.items;
+ out->numberofcorners = (b->order + 1) * (b->order + 2) / 2;
+ out->numberoftriangleattributes = m.eextras;
+ out->numberofedges = m.edges;
+ if (b->usesegments) {
+ out->numberofsegments = m.subsegs.items;
+ }
+ else {
+ out->numberofsegments = m.hullsize;
+ }
+ if (vorout != (struct triangulateio *) NULL) {
+ vorout->numberofpoints = m.triangles.items;
+ vorout->numberofpointattributes = m.nextras;
+ vorout->numberofedges = m.edges;
+ }
+
+ /* If not using iteration numbers, don't write a .node file if one was */
+ /* read, because the original one would be overwritten! */
+ if (b->nonodewritten || (b->noiterationnum && m.readnodefile)) {
+ if (!b->quiet) {
+ printf("NOT writing vertices.\n");
+ }
+ numbernodes(&m, b); /* We must remember to number the vertices. */
+ }
+ else {
+ /* writenodes() numbers the vertices too. */
+ writenodes(&m, b, &out->pointlist, &out->pointattributelist, &out->pointmarkerlist);
+ }
+ if (b->noelewritten) {
+ if (!b->quiet) {
+ printf("NOT writing triangles.\n");
+ }
+ }
+ else {
+ writeelements(&m, b, &out->trianglelist, &out->triangleattributelist);
+ }
+ /* The -c switch (convex switch) causes a PSLG to be written */
+ /* even if none was read. */
+ if (b->poly || b->convex) {
+ /* If not using iteration numbers, don't overwrite the .poly file. */
+ if (b->nopolywritten || b->noiterationnum) {
+ if (!b->quiet) {
+ printf("NOT writing segments.\n");
+ }
+ }
+ else {
+ writepoly(&m, b, &out->segmentlist, &out->segmentmarkerlist);
+ out->numberofholes = m.holes;
+ out->numberofregions = m.regions;
+ if (b->poly) {
+ out->holelist = in->holelist;
+ out->regionlist = in->regionlist;
+ }
+ else {
+ out->holelist = (REAL *) NULL;
+ out->regionlist = (REAL *) NULL;
+ }
+ }
+ }
+ if (b->edgesout) {
+ writeedges(&m, b, &out->edgelist, &out->edgemarkerlist);
+ }
+ if (b->voronoi) {
+ writevoronoi(&m, b, &vorout->pointlist, &vorout->pointattributelist, &vorout->pointmarkerlist,
+ &vorout->edgelist, &vorout->edgemarkerlist, &vorout->normlist);
+ }
+ if (b->neighbors) {
+ writeneighbors(&m, b, &out->neighborlist);
+ }
+
+ if (!b->quiet) {
+ statistics(&m, b);
+ }
+
+#ifndef REDUCED
+ if (b->docheck)
+ {
+ checkmesh(&m, b);
+ checkdelaunay(&m, b);
+ }
+#endif /* not REDUCED */
+
+ triangledeinit(&m, b);
+}
diff --git a/vtm/jni/target/linux64/triangle/triangle_dbg.c b/vtm/jni/target/linux64/triangle/triangle_dbg.c
new file mode 100644
index 00000000..f6374ba3
--- /dev/null
+++ b/vtm/jni/target/linux64/triangle/triangle_dbg.c
@@ -0,0 +1,441 @@
+#include "triangle_private.h"
+
+/*****************************************************************************/
+/* */
+/* quality_statistics() Print statistics about the quality of the mesh. */
+/* */
+/*****************************************************************************/
+
+void quality_statistics(struct mesh *m, struct behavior *b) {
+ struct otri triangleloop;
+ vertex p[3];
+ REAL cossquaretable[8];
+ REAL ratiotable[16];
+ REAL dx[3], dy[3];
+ REAL edgelength[3];
+ REAL dotproduct;
+ REAL cossquare;
+ REAL triarea;
+ REAL shortest, longest;
+ REAL trilongest2;
+ REAL smallestarea, biggestarea;
+ REAL triminaltitude2;
+ REAL minaltitude;
+ REAL triaspect2;
+ REAL worstaspect;
+ REAL smallestangle, biggestangle;
+ REAL radconst, degconst;
+ int angletable[18];
+ int aspecttable[16];
+ int aspectindex;
+ int tendegree;
+ int acutebiggest;
+ int i, ii, j, k;
+
+ printf("Mesh quality statistics:\n\n");
+ radconst = PI / 18.0;
+ degconst = 180.0 / PI;
+ for (i = 0; i < 8; i++) {
+ cossquaretable[i] = cos(radconst * (REAL) (i + 1));
+ cossquaretable[i] = cossquaretable[i] * cossquaretable[i];
+ }
+ for (i = 0; i < 18; i++) {
+ angletable[i] = 0;
+ }
+
+ ratiotable[0] = 1.5;
+ ratiotable[1] = 2.0;
+ ratiotable[2] = 2.5;
+ ratiotable[3] = 3.0;
+ ratiotable[4] = 4.0;
+ ratiotable[5] = 6.0;
+ ratiotable[6] = 10.0;
+ ratiotable[7] = 15.0;
+ ratiotable[8] = 25.0;
+ ratiotable[9] = 50.0;
+ ratiotable[10] = 100.0;
+ ratiotable[11] = 300.0;
+ ratiotable[12] = 1000.0;
+ ratiotable[13] = 10000.0;
+ ratiotable[14] = 100000.0;
+ ratiotable[15] = 0.0;
+ for (i = 0; i < 16; i++) {
+ aspecttable[i] = 0;
+ }
+
+ worstaspect = 0.0;
+ minaltitude = m->xmax - m->xmin + m->ymax - m->ymin;
+ minaltitude = minaltitude * minaltitude;
+ shortest = minaltitude;
+ longest = 0.0;
+ smallestarea = minaltitude;
+ biggestarea = 0.0;
+ worstaspect = 0.0;
+ smallestangle = 0.0;
+ biggestangle = 2.0;
+ acutebiggest = 1;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ while (triangleloop.tri != (triangle *) NULL) {
+ org(triangleloop, p[0]);
+ dest(triangleloop, p[1]);
+ apex(triangleloop, p[2]);
+ trilongest2 = 0.0;
+
+ for (i = 0; i < 3; i++) {
+ j = plus1mod3[i];
+ k = minus1mod3[i];
+ dx[i] = p[j][0] - p[k][0];
+ dy[i] = p[j][1] - p[k][1];
+ edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i];
+ if (edgelength[i] > trilongest2) {
+ trilongest2 = edgelength[i];
+ }
+ if (edgelength[i] > longest) {
+ longest = edgelength[i];
+ }
+ if (edgelength[i] < shortest) {
+ shortest = edgelength[i];
+ }
+ }
+
+ triarea = counterclockwise(m, b, p[0], p[1], p[2]);
+ if (triarea < smallestarea) {
+ smallestarea = triarea;
+ }
+ if (triarea > biggestarea) {
+ biggestarea = triarea;
+ }
+ triminaltitude2 = triarea * triarea / trilongest2;
+ if (triminaltitude2 < minaltitude) {
+ minaltitude = triminaltitude2;
+ }
+ triaspect2 = trilongest2 / triminaltitude2;
+ if (triaspect2 > worstaspect) {
+ worstaspect = triaspect2;
+ }
+ aspectindex = 0;
+ while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) && (aspectindex < 15)) {
+ aspectindex++;
+ }
+ aspecttable[aspectindex]++;
+
+ for (i = 0; i < 3; i++) {
+ j = plus1mod3[i];
+ k = minus1mod3[i];
+ dotproduct = dx[j] * dx[k] + dy[j] * dy[k];
+ cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]);
+ tendegree = 8;
+ for (ii = 7; ii >= 0; ii--) {
+ if (cossquare > cossquaretable[ii]) {
+ tendegree = ii;
+ }
+ }
+ if (dotproduct <= 0.0) {
+ angletable[tendegree]++;
+ if (cossquare > smallestangle) {
+ smallestangle = cossquare;
+ }
+ if (acutebiggest && (cossquare < biggestangle)) {
+ biggestangle = cossquare;
+ }
+ }
+ else {
+ angletable[17 - tendegree]++;
+ if (acutebiggest || (cossquare > biggestangle)) {
+ biggestangle = cossquare;
+ acutebiggest = 0;
+ }
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+
+ shortest = sqrt(shortest);
+ longest = sqrt(longest);
+ minaltitude = sqrt(minaltitude);
+ worstaspect = sqrt(worstaspect);
+ smallestarea *= 0.5;
+ biggestarea *= 0.5;
+ if (smallestangle >= 1.0) {
+ smallestangle = 0.0;
+ }
+ else {
+ smallestangle = degconst * acos(sqrt(smallestangle));
+ }
+ if (biggestangle >= 1.0) {
+ biggestangle = 180.0;
+ }
+ else {
+ if (acutebiggest) {
+ biggestangle = degconst * acos(sqrt(biggestangle));
+ }
+ else {
+ biggestangle = 180.0 - degconst * acos(sqrt(biggestangle));
+ }
+ }
+
+ printf(" Smallest area: %16.5g | Largest area: %16.5g\n", smallestarea, biggestarea);
+ printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", shortest, longest);
+ printf(
+ " Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", minaltitude, worstaspect);
+
+ printf(" Triangle aspect ratio histogram:\n");
+ printf(
+ " 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], aspecttable[8]);
+ for (i = 1; i < 7; i++) {
+ printf(
+ " %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", ratiotable[i - 1], ratiotable[i], aspecttable[i], ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]);
+ }
+ printf(
+ " %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], aspecttable[15]);
+ printf(" (Aspect ratio is longest edge divided by shortest altitude)\n\n");
+
+ printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", smallestangle, biggestangle);
+
+ printf(" Angle histogram:\n");
+ for (i = 0; i < 9; i++) {
+ printf(
+ " %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", i * 10, i * 10 + 10, angletable[i], i * 10 + 90, i * 10 + 100, angletable[i + 9]);
+ }
+ printf("\n");
+}
+
+/*****************************************************************************/
+/* */
+/* statistics() Print all sorts of cool facts. */
+/* */
+/*****************************************************************************/
+
+void statistics(struct mesh *m, struct behavior *b) {
+ printf("\nStatistics:\n\n");
+ printf(" Input vertices: %d\n", m->invertices);
+ if (b->refine) {
+ printf(" Input triangles: %d\n", m->inelements);
+ }
+ if (b->poly) {
+ printf(" Input segments: %d\n", m->insegments);
+ if (!b->refine) {
+ printf(" Input holes: %d\n", m->holes);
+ }
+ }
+
+ printf("\n Mesh vertices: %ld\n", m->vertices.items - m->undeads);
+ printf(" Mesh triangles: %ld\n", m->triangles.items);
+ printf(" Mesh edges: %ld\n", m->edges);
+ printf(" Mesh exterior boundary edges: %ld\n", m->hullsize);
+ if (b->poly || b->refine) {
+ printf(" Mesh interior boundary edges: %ld\n", m->subsegs.items - m->hullsize);
+ printf(" Mesh subsegments (constrained edges): %ld\n", m->subsegs.items);
+ }
+ printf("\n");
+
+ if (b->verbose) {
+ quality_statistics(m, b);
+ printf("Memory allocation statistics:\n\n");
+ printf(" Maximum number of vertices: %ld\n", m->vertices.maxitems);
+ printf(" Maximum number of triangles: %ld\n", m->triangles.maxitems);
+ if (m->subsegs.maxitems > 0) {
+ printf(" Maximum number of subsegments: %ld\n", m->subsegs.maxitems);
+ }
+ if (m->viri.maxitems > 0) {
+ printf(" Maximum number of viri: %ld\n", m->viri.maxitems);
+ }
+ if (m->badsubsegs.maxitems > 0) {
+ printf(" Maximum number of encroached subsegments: %ld\n", m->badsubsegs.maxitems);
+ }
+ if (m->badtriangles.maxitems > 0) {
+ printf(" Maximum number of bad triangles: %ld\n", m->badtriangles.maxitems);
+ }
+ if (m->flipstackers.maxitems > 0) {
+ printf(" Maximum number of stacked triangle flips: %ld\n", m->flipstackers.maxitems);
+ }
+ if (m->splaynodes.maxitems > 0) {
+ printf(" Maximum number of splay tree nodes: %ld\n", m->splaynodes.maxitems);
+ }
+ printf(
+ " Approximate heap memory use (bytes): %ld\n\n", m->vertices.maxitems * m->vertices.itembytes + m->triangles.maxitems * m->triangles.itembytes + m->subsegs.maxitems * m->subsegs.itembytes + m->viri.maxitems * m->viri.itembytes + m->badsubsegs.maxitems * m->badsubsegs.itembytes + m->badtriangles.maxitems * m->badtriangles.itembytes + m->flipstackers.maxitems * m->flipstackers.itembytes + m->splaynodes.maxitems * m->splaynodes.itembytes);
+
+ printf("Algorithmic statistics:\n\n");
+ if (!b->weighted) {
+ printf(" Number of incircle tests: %ld\n", m->incirclecount);
+ }
+ else {
+ printf(" Number of 3D orientation tests: %ld\n", m->orient3dcount);
+ }
+ printf(" Number of 2D orientation tests: %ld\n", m->counterclockcount);
+ if (m->hyperbolacount > 0) {
+ printf(" Number of right-of-hyperbola tests: %ld\n", m->hyperbolacount);
+ }
+ if (m->circletopcount > 0) {
+ printf(" Number of circle top computations: %ld\n", m->circletopcount);
+ }
+ if (m->circumcentercount > 0) {
+ printf(" Number of triangle circumcenter computations: %ld\n", m->circumcentercount);
+ }
+ printf("\n");
+ }
+}
+
+/********* Debugging routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* printtriangle() Print out the details of an oriented triangle. */
+/* */
+/* I originally wrote this procedure to simplify debugging; it can be */
+/* called directly from the debugger, and presents information about an */
+/* oriented triangle in digestible form. It's also used when the */
+/* highest level of verbosity (`-VVV') is specified. */
+/* */
+/*****************************************************************************/
+
+void printtriangle(struct mesh *m, struct behavior *b, struct otri *t) {
+ struct otri printtri;
+ struct osub printsh;
+ vertex printvertex;
+
+ printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, t->orient);
+ decode(t->tri[0], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [0] = Outer space\n");
+ }
+ else {
+ printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+ decode(t->tri[1], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [1] = Outer space\n");
+ }
+ else {
+ printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+ decode(t->tri[2], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [2] = Outer space\n");
+ }
+ else {
+ printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+
+ org(*t, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3);
+ else
+ printf(
+ " Origin[%d] = x%lx (%.12g, %.12g)\n", (t->orient + 1) % 3 + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ dest(*t, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3);
+ else
+ printf(
+ " Dest [%d] = x%lx (%.12g, %.12g)\n", (t->orient + 2) % 3 + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ apex(*t, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Apex [%d] = NULL\n", t->orient + 3);
+ else
+ printf(
+ " Apex [%d] = x%lx (%.12g, %.12g)\n", t->orient + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+
+ if (b->usesegments) {
+ sdecode(t->tri[6], printsh);
+ if (printsh.ss != m->dummysub) {
+ printf(" [6] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ sdecode(t->tri[7], printsh);
+ if (printsh.ss != m->dummysub) {
+ printf(" [7] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ sdecode(t->tri[8], printsh);
+ if (printsh.ss != m->dummysub) {
+ printf(" [8] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ }
+
+ if (b->vararea) {
+ printf(" Area constraint: %.4g\n", areabound(*t));
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* printsubseg() Print out the details of an oriented subsegment. */
+/* */
+/* I originally wrote this procedure to simplify debugging; it can be */
+/* called directly from the debugger, and presents information about an */
+/* oriented subsegment in digestible form. It's also used when the highest */
+/* level of verbosity (`-VVV') is specified. */
+/* */
+/*****************************************************************************/
+
+void printsubseg(struct mesh *m, struct behavior *b, struct osub *s) {
+ struct osub printsh;
+ struct otri printtri;
+ vertex printvertex;
+
+ printf(
+ "subsegment x%lx with orientation %d and mark %d:\n", (unsigned long) s->ss, s->ssorient, mark(*s));
+ sdecode(s->ss[0], printsh);
+ if (printsh.ss == m->dummysub) {
+ printf(" [0] = No subsegment\n");
+ }
+ else {
+ printf(" [0] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ sdecode(s->ss[1], printsh);
+ if (printsh.ss == m->dummysub) {
+ printf(" [1] = No subsegment\n");
+ }
+ else {
+ printf(" [1] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+
+ sorg(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Origin[%d] = NULL\n", 2 + s->ssorient);
+ else
+ printf(
+ " Origin[%d] = x%lx (%.12g, %.12g)\n", 2 + s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ sdest(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Dest [%d] = NULL\n", 3 - s->ssorient);
+ else
+ printf(
+ " Dest [%d] = x%lx (%.12g, %.12g)\n", 3 - s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+
+ decode(s->ss[6], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [6] = Outer space\n");
+ }
+ else {
+ printf(" [6] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+ decode(s->ss[7], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [7] = Outer space\n");
+ }
+ else {
+ printf(" [7] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+
+ segorg(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Segment origin[%d] = NULL\n", 4 + s->ssorient);
+ else
+ printf(
+ " Segment origin[%d] = x%lx (%.12g, %.12g)\n", 4 + s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ segdest(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Segment dest [%d] = NULL\n", 5 - s->ssorient);
+ else
+ printf(
+ " Segment dest [%d] = x%lx (%.12g, %.12g)\n", 5 - s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+}
+
+/** **/
+/** **/
+/********* Debugging routines end here *********/
diff --git a/vtm/jni/tessellate/LICENSE b/vtm/jni/tessellate/LICENSE
new file mode 100644
index 00000000..fd57cadc
--- /dev/null
+++ b/vtm/jni/tessellate/LICENSE
@@ -0,0 +1,37 @@
+Copyright notice and license for the libtess files (all source files besides
+tessellate.[ch] and main.c):
+
+SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice including the dates of first publication and
+either this permission notice or a reference to
+http://oss.sgi.com/projects/FreeB/
+shall be included in all copies or substantial portions of the Software.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Except as contained in this notice, the name of Silicon Graphics, Inc.
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization from
+Silicon Graphics, Inc.
+
+--------------------------------------------------------------------------------
+
+Copyright notice for the other files:
+
+SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+Copyright (C) 2013 AT&T Intellectual Property. All Rights Reserved.
diff --git a/vtm/jni/tessellate/Makefile b/vtm/jni/tessellate/Makefile
new file mode 100644
index 00000000..607753f6
--- /dev/null
+++ b/vtm/jni/tessellate/Makefile
@@ -0,0 +1,2 @@
+all:
+ gcc dict.c mesh.c render.c tess.c geom.c memalloc.c normal.c priorityq.c sweep.c tessmono.c tessellate.c main.c -o tessellate
diff --git a/vtm/jni/tessellate/README.md b/vtm/jni/tessellate/README.md
new file mode 100644
index 00000000..fef24f33
--- /dev/null
+++ b/vtm/jni/tessellate/README.md
@@ -0,0 +1,18 @@
+# A minimal, self-contained port of SGI's GLU libtess
+
+Polygon tessellation is a major pain in the neck. Have you ever tried
+writing fast and robust code for it? libtess is, to my knowledge, the
+only GPL-compatible, liberally-licensed, high-quality polygon
+triangulator out there.
+
+This repository includes a self-contained function (tessellate, in
+tessellate.c) that you can call to triangulate a polygon that is
+potentially self-intersecting, with holes, or with duplicate
+vertices. Simple examples of calling the tessellate function directly
+are located in main.c.
+
+More interestingly, this repository also includes an
+Emscripten-compiled module, _tessellate.js, and a Javascript-friendly
+wrapper, in tessellate.js. Simple examples are available under
+index.html.
+
diff --git a/vtm/jni/tessellate/dict-list.h b/vtm/jni/tessellate/dict-list.h
new file mode 100644
index 00000000..11331a76
--- /dev/null
+++ b/vtm/jni/tessellate/dict-list.h
@@ -0,0 +1,100 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/vtm/jni/tessellate/dict.c b/vtm/jni/tessellate/dict.c
new file mode 100644
index 00000000..49d4f759
--- /dev/null
+++ b/vtm/jni/tessellate/dict.c
@@ -0,0 +1,111 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include
+#include "dict-list.h"
+#include "memalloc.h"
+
+/* really __gl_dictListNewDict */
+Dict *dictNewDict( void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) )
+{
+ Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
+ DictNode *head;
+
+ if (dict == NULL) return NULL;
+
+ head = &dict->head;
+
+ head->key = NULL;
+ head->next = head;
+ head->prev = head;
+
+ dict->frame = frame;
+ dict->leq = leq;
+
+ return dict;
+}
+
+/* really __gl_dictListDeleteDict */
+void dictDeleteDict( Dict *dict )
+{
+ DictNode *node, *next;
+
+ for( node = dict->head.next; node != &dict->head; node = next ) {
+ next = node->next;
+ memFree( node );
+ }
+ memFree( dict );
+}
+
+/* really __gl_dictListInsertBefore */
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key )
+{
+ DictNode *newNode;
+
+ do {
+ node = node->prev;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
+
+ newNode = (DictNode *) memAlloc( sizeof( DictNode ));
+ if (newNode == NULL) return NULL;
+
+ newNode->key = key;
+ newNode->next = node->next;
+ node->next->prev = newNode;
+ newNode->prev = node;
+ node->next = newNode;
+
+ return newNode;
+}
+
+/* really __gl_dictListDelete */
+void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/
+{
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ memFree( node );
+}
+
+/* really __gl_dictListSearch */
+DictNode *dictSearch( Dict *dict, DictKey key )
+{
+ DictNode *node = &dict->head;
+
+ do {
+ node = node->next;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
+
+ return node;
+}
diff --git a/vtm/jni/tessellate/dict.h b/vtm/jni/tessellate/dict.h
new file mode 100644
index 00000000..11331a76
--- /dev/null
+++ b/vtm/jni/tessellate/dict.h
@@ -0,0 +1,100 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/vtm/jni/tessellate/geom.c b/vtm/jni/tessellate/geom.c
new file mode 100644
index 00000000..35b36a39
--- /dev/null
+++ b/vtm/jni/tessellate/geom.c
@@ -0,0 +1,264 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include
+#include "mesh.h"
+#include "geom.h"
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
+{
+ /* Returns TRUE if u is lexicographically <= v. */
+
+ return VertLeq( u, v );
+}
+
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->t = 0 and
+ * let r be the negated result (this evaluates (uw)(v->s)), then
+ * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
+ } else {
+ return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches EdgeEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+/***********************************************************************
+ * Define versions of EdgeSign, EdgeEval with s and t transposed.
+ */
+
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->s = 0 and
+ * let r be the negated result (this evaluates (uw)(v->t)), then
+ * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
+ } else {
+ return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches TransEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* For almost-degenerate situations, the results are not reliable.
+ * Unless the floating-point arithmetic can be performed without
+ * rounding errors, *any* implementation will give incorrect results
+ * on some degenerate inputs, so the client must have some way to
+ * handle this situation.
+ */
+ return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
+}
+
+/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
+ * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
+ * this in the rare case that one argument is slightly negative.
+ * The implementation is extremely stable numerically.
+ * In particular it guarantees that the result r satisfies
+ * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
+ * even when a and b differ greatly in magnitude.
+ */
+#define RealInterpolate(a,x,b,y) \
+ (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
+ ((a <= b) ? ((b == 0) ? ((x+y) / 2) \
+ : (x + (y-x) * (a/(a+b)))) \
+ : (y + (x-y) * (b/(a+b)))))
+
+#ifndef FOR_TRITE_TEST_PROGRAM
+#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y)
+#else
+
+/* Claim: the ONLY property the sweep algorithm relies on is that
+ * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that.
+ */
+#include
+extern int RandomInterpolate;
+
+GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
+{
+printf("*********************%d\n",RandomInterpolate);
+ if( RandomInterpolate ) {
+ a = 1.2 * drand48() - 0.1;
+ a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
+ b = 1.0 - a;
+ }
+ return RealInterpolate(a,x,b,y);
+}
+
+#endif
+
+#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while (0)
+
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v )
+/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
+ * The computed point is guaranteed to lie in the intersection of the
+ * bounding rectangles defined by each edge.
+ */
+{
+ GLdouble z1, z2;
+
+ /* This is certainly not the most efficient way to find the intersection
+ * of two line segments, but it is very numerically stable.
+ *
+ * Strategy: find the two middle vertices in the VertLeq ordering,
+ * and interpolate the intersection s-value from these. Then repeat
+ * using the TransLeq ordering to find the intersection t-value.
+ */
+
+ if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! VertLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->s = (o2->s + d1->s) / 2;
+ } else if( VertLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = EdgeEval( o1, o2, d1 );
+ z2 = EdgeEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d1->s );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = EdgeSign( o1, o2, d1 );
+ z2 = -EdgeSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d2->s );
+ }
+
+ /* Now repeat the process for t */
+
+ if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! TransLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->t = (o2->t + d1->t) / 2;
+ } else if( TransLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = TransEval( o1, o2, d1 );
+ z2 = TransEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d1->t );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = TransSign( o1, o2, d1 );
+ z2 = -TransSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d2->t );
+ }
+}
diff --git a/vtm/jni/tessellate/geom.h b/vtm/jni/tessellate/geom.h
new file mode 100644
index 00000000..5cb76c7d
--- /dev/null
+++ b/vtm/jni/tessellate/geom.h
@@ -0,0 +1,84 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __geom_h_
+#define __geom_h_
+
+#include "mesh.h"
+
+#ifdef NO_BRANCH_CONDITIONS
+/* MIPS architecture has special instructions to evaluate boolean
+ * conditions -- more efficient than branching, IF you can get the
+ * compiler to generate the right instructions (SGI compiler doesn't)
+ */
+#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t))
+#define VertLeq(u,v) (((u)->s < (v)->s) | \
+ ((u)->s == (v)->s & (u)->t <= (v)->t))
+#else
+#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t)
+#define VertLeq(u,v) (((u)->s < (v)->s) || \
+ ((u)->s == (v)->s && (u)->t <= (v)->t))
+#endif
+
+#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
+#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
+
+/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
+
+#define TransLeq(u,v) (((u)->t < (v)->t) || \
+ ((u)->t == (v)->t && (u)->s <= (v)->s))
+#define TransEval(u,v,w) __gl_transEval(u,v,w)
+#define TransSign(u,v,w) __gl_transSign(u,v,w)
+
+
+#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org )
+#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst )
+
+#undef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t))
+
+#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v );
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v );
+
+#endif
diff --git a/vtm/jni/tessellate/glu.h b/vtm/jni/tessellate/glu.h
new file mode 100644
index 00000000..fe88e7e1
--- /dev/null
+++ b/vtm/jni/tessellate/glu.h
@@ -0,0 +1,356 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+
+#ifndef __glu_h__
+#define __glu_h__
+
+#define GLAPIENTRYP *
+#define GLAPIENTRY
+#define GLAPI
+
+typedef int GLint;
+typedef unsigned int GLenum;
+typedef unsigned int GLsizei;
+typedef float GLfloat;
+typedef double GLdouble;
+typedef unsigned char GLubyte;
+typedef int GLboolean;
+typedef void GLvoid;
+
+#define GL_FALSE 0
+#define GL_TRUE 1
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+// #if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GLU32)
+// # undef GLAPI
+// # define GLAPI __declspec(dllexport)
+// #elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL)
+// /* tag specifying we're building for DLL runtime support */
+// # undef GLAPI
+// # define GLAPI __declspec(dllimport)
+// #elif !defined(GLAPI)
+// /* for use with static link lib build of Win32 edition only */
+// # define GLAPI extern
+// #endif /* _STATIC_MESA support */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************/
+
+/* Extensions */
+#define GLU_EXT_object_space_tess 1
+#define GLU_EXT_nurbs_tessellator 1
+
+/* Boolean */
+#define GLU_FALSE 0
+#define GLU_TRUE 1
+
+/* Version */
+#define GLU_VERSION_1_1 1
+#define GLU_VERSION_1_2 1
+#define GLU_VERSION_1_3 1
+
+/* StringName */
+#define GLU_VERSION 100800
+#define GLU_EXTENSIONS 100801
+
+/* ErrorCode */
+#define GLU_INVALID_ENUM 100900
+#define GLU_INVALID_VALUE 100901
+#define GLU_OUT_OF_MEMORY 100902
+#define GLU_INCOMPATIBLE_GL_VERSION 100903
+#define GLU_INVALID_OPERATION 100904
+
+/* NurbsDisplay */
+/* GLU_FILL */
+#define GLU_OUTLINE_POLYGON 100240
+#define GLU_OUTLINE_PATCH 100241
+
+/* NurbsCallback */
+#define GLU_NURBS_ERROR 100103
+#define GLU_ERROR 100103
+#define GLU_NURBS_BEGIN 100164
+#define GLU_NURBS_BEGIN_EXT 100164
+#define GLU_NURBS_VERTEX 100165
+#define GLU_NURBS_VERTEX_EXT 100165
+#define GLU_NURBS_NORMAL 100166
+#define GLU_NURBS_NORMAL_EXT 100166
+#define GLU_NURBS_COLOR 100167
+#define GLU_NURBS_COLOR_EXT 100167
+#define GLU_NURBS_TEXTURE_COORD 100168
+#define GLU_NURBS_TEX_COORD_EXT 100168
+#define GLU_NURBS_END 100169
+#define GLU_NURBS_END_EXT 100169
+#define GLU_NURBS_BEGIN_DATA 100170
+#define GLU_NURBS_BEGIN_DATA_EXT 100170
+#define GLU_NURBS_VERTEX_DATA 100171
+#define GLU_NURBS_VERTEX_DATA_EXT 100171
+#define GLU_NURBS_NORMAL_DATA 100172
+#define GLU_NURBS_NORMAL_DATA_EXT 100172
+#define GLU_NURBS_COLOR_DATA 100173
+#define GLU_NURBS_COLOR_DATA_EXT 100173
+#define GLU_NURBS_TEXTURE_COORD_DATA 100174
+#define GLU_NURBS_TEX_COORD_DATA_EXT 100174
+#define GLU_NURBS_END_DATA 100175
+#define GLU_NURBS_END_DATA_EXT 100175
+
+/* NurbsError */
+#define GLU_NURBS_ERROR1 100251
+#define GLU_NURBS_ERROR2 100252
+#define GLU_NURBS_ERROR3 100253
+#define GLU_NURBS_ERROR4 100254
+#define GLU_NURBS_ERROR5 100255
+#define GLU_NURBS_ERROR6 100256
+#define GLU_NURBS_ERROR7 100257
+#define GLU_NURBS_ERROR8 100258
+#define GLU_NURBS_ERROR9 100259
+#define GLU_NURBS_ERROR10 100260
+#define GLU_NURBS_ERROR11 100261
+#define GLU_NURBS_ERROR12 100262
+#define GLU_NURBS_ERROR13 100263
+#define GLU_NURBS_ERROR14 100264
+#define GLU_NURBS_ERROR15 100265
+#define GLU_NURBS_ERROR16 100266
+#define GLU_NURBS_ERROR17 100267
+#define GLU_NURBS_ERROR18 100268
+#define GLU_NURBS_ERROR19 100269
+#define GLU_NURBS_ERROR20 100270
+#define GLU_NURBS_ERROR21 100271
+#define GLU_NURBS_ERROR22 100272
+#define GLU_NURBS_ERROR23 100273
+#define GLU_NURBS_ERROR24 100274
+#define GLU_NURBS_ERROR25 100275
+#define GLU_NURBS_ERROR26 100276
+#define GLU_NURBS_ERROR27 100277
+#define GLU_NURBS_ERROR28 100278
+#define GLU_NURBS_ERROR29 100279
+#define GLU_NURBS_ERROR30 100280
+#define GLU_NURBS_ERROR31 100281
+#define GLU_NURBS_ERROR32 100282
+#define GLU_NURBS_ERROR33 100283
+#define GLU_NURBS_ERROR34 100284
+#define GLU_NURBS_ERROR35 100285
+#define GLU_NURBS_ERROR36 100286
+#define GLU_NURBS_ERROR37 100287
+
+/* NurbsProperty */
+#define GLU_AUTO_LOAD_MATRIX 100200
+#define GLU_CULLING 100201
+#define GLU_SAMPLING_TOLERANCE 100203
+#define GLU_DISPLAY_MODE 100204
+#define GLU_PARAMETRIC_TOLERANCE 100202
+#define GLU_SAMPLING_METHOD 100205
+#define GLU_U_STEP 100206
+#define GLU_V_STEP 100207
+#define GLU_NURBS_MODE 100160
+#define GLU_NURBS_MODE_EXT 100160
+#define GLU_NURBS_TESSELLATOR 100161
+#define GLU_NURBS_TESSELLATOR_EXT 100161
+#define GLU_NURBS_RENDERER 100162
+#define GLU_NURBS_RENDERER_EXT 100162
+
+/* NurbsSampling */
+#define GLU_OBJECT_PARAMETRIC_ERROR 100208
+#define GLU_OBJECT_PARAMETRIC_ERROR_EXT 100208
+#define GLU_OBJECT_PATH_LENGTH 100209
+#define GLU_OBJECT_PATH_LENGTH_EXT 100209
+#define GLU_PATH_LENGTH 100215
+#define GLU_PARAMETRIC_ERROR 100216
+#define GLU_DOMAIN_DISTANCE 100217
+
+/* NurbsTrim */
+#define GLU_MAP1_TRIM_2 100210
+#define GLU_MAP1_TRIM_3 100211
+
+/* QuadricDrawStyle */
+#define GLU_POINT 100010
+#define GLU_LINE 100011
+#define GLU_FILL 100012
+#define GLU_SILHOUETTE 100013
+
+/* QuadricCallback */
+/* GLU_ERROR */
+
+/* QuadricNormal */
+#define GLU_SMOOTH 100000
+#define GLU_FLAT 100001
+#define GLU_NONE 100002
+
+/* QuadricOrientation */
+#define GLU_OUTSIDE 100020
+#define GLU_INSIDE 100021
+
+/* TessCallback */
+#define GLU_TESS_BEGIN 100100
+#define GLU_BEGIN 100100
+#define GLU_TESS_VERTEX 100101
+#define GLU_VERTEX 100101
+#define GLU_TESS_END 100102
+#define GLU_END 100102
+#define GLU_TESS_ERROR 100103
+#define GLU_TESS_EDGE_FLAG 100104
+#define GLU_EDGE_FLAG 100104
+#define GLU_TESS_COMBINE 100105
+#define GLU_TESS_BEGIN_DATA 100106
+#define GLU_TESS_VERTEX_DATA 100107
+#define GLU_TESS_END_DATA 100108
+#define GLU_TESS_ERROR_DATA 100109
+#define GLU_TESS_EDGE_FLAG_DATA 100110
+#define GLU_TESS_COMBINE_DATA 100111
+
+/* TessContour */
+#define GLU_CW 100120
+#define GLU_CCW 100121
+#define GLU_INTERIOR 100122
+#define GLU_EXTERIOR 100123
+#define GLU_UNKNOWN 100124
+
+/* TessProperty */
+#define GLU_TESS_WINDING_RULE 100140
+#define GLU_TESS_BOUNDARY_ONLY 100141
+#define GLU_TESS_TOLERANCE 100142
+
+/* TessError */
+#define GLU_TESS_ERROR1 100151
+#define GLU_TESS_ERROR2 100152
+#define GLU_TESS_ERROR3 100153
+#define GLU_TESS_ERROR4 100154
+#define GLU_TESS_ERROR5 100155
+#define GLU_TESS_ERROR6 100156
+#define GLU_TESS_ERROR7 100157
+#define GLU_TESS_ERROR8 100158
+#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
+#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
+#define GLU_TESS_MISSING_END_POLYGON 100153
+#define GLU_TESS_MISSING_END_CONTOUR 100154
+#define GLU_TESS_COORD_TOO_LARGE 100155
+#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
+
+/* TessWinding */
+#define GLU_TESS_WINDING_ODD 100130
+#define GLU_TESS_WINDING_NONZERO 100131
+#define GLU_TESS_WINDING_POSITIVE 100132
+#define GLU_TESS_WINDING_NEGATIVE 100133
+#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
+
+/*************************************************************/
+
+
+#ifdef __cplusplus
+class GLUnurbs;
+class GLUquadric;
+class GLUtesselator;
+#else
+typedef struct GLUnurbs GLUnurbs;
+typedef struct GLUquadric GLUquadric;
+typedef struct GLUtesselator GLUtesselator;
+#endif
+
+typedef GLUnurbs GLUnurbsObj;
+typedef GLUquadric GLUquadricObj;
+typedef GLUtesselator GLUtesselatorObj;
+typedef GLUtesselator GLUtriangulatorObj;
+
+#define GLU_TESS_MAX_COORD 1.0e150
+
+/* Internal convenience typedefs */
+typedef void (GLAPIENTRYP _GLUfuncptr)(void);
+
+GLAPI void GLAPIENTRY gluBeginCurve (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluBeginPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluBeginSurface (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluBeginTrim (GLUnurbs* nurb);
+GLAPI GLint GLAPIENTRY gluBuild1DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild2DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild3DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
+GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+GLAPI GLboolean GLAPIENTRY gluCheckExtension (const GLubyte *extName, const GLubyte *extString);
+GLAPI void GLAPIENTRY gluCylinder (GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks);
+GLAPI void GLAPIENTRY gluDeleteNurbsRenderer (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluDeleteQuadric (GLUquadric* quad);
+GLAPI void GLAPIENTRY gluDeleteTess (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops);
+GLAPI void GLAPIENTRY gluEndCurve (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluEndPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluEndSurface (GLUnurbs* nurb);
+GLAPI void GLAPIENTRY gluEndTrim (GLUnurbs* nurb);
+GLAPI const GLubyte * GLAPIENTRY gluErrorString (GLenum error);
+GLAPI void GLAPIENTRY gluGetNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat* data);
+GLAPI const GLubyte * GLAPIENTRY gluGetString (GLenum name);
+GLAPI void GLAPIENTRY gluGetTessProperty (GLUtesselator* tess, GLenum which, GLdouble* data);
+GLAPI void GLAPIENTRY gluLoadSamplingMatrices (GLUnurbs* nurb, const GLfloat *model, const GLfloat *perspective, const GLint *view);
+GLAPI void GLAPIENTRY gluLookAt (GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ);
+GLAPI GLUnurbs* GLAPIENTRY gluNewNurbsRenderer (void);
+GLAPI GLUquadric* GLAPIENTRY gluNewQuadric (void);
+GLAPI GLUtesselator* GLAPIENTRY gluNewTess (void);
+GLAPI void GLAPIENTRY gluNextContour (GLUtesselator* tess, GLenum type);
+GLAPI void GLAPIENTRY gluNurbsCallback (GLUnurbs* nurb, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluNurbsCallbackData (GLUnurbs* nurb, GLvoid* userData);
+GLAPI void GLAPIENTRY gluNurbsCallbackDataEXT (GLUnurbs* nurb, GLvoid* userData);
+GLAPI void GLAPIENTRY gluNurbsCurve (GLUnurbs* nurb, GLint knotCount, GLfloat *knots, GLint stride, GLfloat *control, GLint order, GLenum type);
+GLAPI void GLAPIENTRY gluNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat value);
+GLAPI void GLAPIENTRY gluNurbsSurface (GLUnurbs* nurb, GLint sKnotCount, GLfloat* sKnots, GLint tKnotCount, GLfloat* tKnots, GLint sStride, GLint tStride, GLfloat* control, GLint sOrder, GLint tOrder, GLenum type);
+GLAPI void GLAPIENTRY gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
+GLAPI void GLAPIENTRY gluPartialDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops, GLdouble start, GLdouble sweep);
+GLAPI void GLAPIENTRY gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
+GLAPI void GLAPIENTRY gluPickMatrix (GLdouble x, GLdouble y, GLdouble delX, GLdouble delY, GLint *viewport);
+GLAPI GLint GLAPIENTRY gluProject (GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* winX, GLdouble* winY, GLdouble* winZ);
+GLAPI void GLAPIENTRY gluPwlCurve (GLUnurbs* nurb, GLint count, GLfloat* data, GLint stride, GLenum type);
+GLAPI void GLAPIENTRY gluQuadricCallback (GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluQuadricDrawStyle (GLUquadric* quad, GLenum draw);
+GLAPI void GLAPIENTRY gluQuadricNormals (GLUquadric* quad, GLenum normal);
+GLAPI void GLAPIENTRY gluQuadricOrientation (GLUquadric* quad, GLenum orientation);
+GLAPI void GLAPIENTRY gluQuadricTexture (GLUquadric* quad, GLboolean texture);
+GLAPI GLint GLAPIENTRY gluScaleImage (GLenum format, GLsizei wIn, GLsizei hIn, GLenum typeIn, const void *dataIn, GLsizei wOut, GLsizei hOut, GLenum typeOut, GLvoid* dataOut);
+GLAPI void GLAPIENTRY gluSphere (GLUquadric* quad, GLdouble radius, GLint slices, GLint stacks);
+GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
+GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
+GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
+GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ);
+GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data);
+GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data);
+GLAPI GLint GLAPIENTRY gluUnProject (GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* objX, GLdouble* objY, GLdouble* objZ);
+GLAPI GLint GLAPIENTRY gluUnProject4 (GLdouble winX, GLdouble winY, GLdouble winZ, GLdouble clipW, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble nearVal, GLdouble farVal, GLdouble* objX, GLdouble* objY, GLdouble* objZ, GLdouble* objW);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glu_h__ */
diff --git a/vtm/jni/tessellate/gluos.h b/vtm/jni/tessellate/gluos.h
new file mode 100644
index 00000000..290a06f0
--- /dev/null
+++ b/vtm/jni/tessellate/gluos.h
@@ -0,0 +1,86 @@
+/*
+** gluos.h - operating system dependencies for GLU
+**
+*/
+#ifdef __VMS
+#ifdef __cplusplus
+#pragma message disable nocordel
+#pragma message disable codeunreachable
+#pragma message disable codcauunr
+#endif
+#endif
+
+#ifdef __WATCOMC__
+/* Disable *lots* of warnings to get a clean build. I can't be bothered fixing the
+ * code at the moment, as it is pretty ugly.
+ */
+#pragma warning 7 10
+#pragma warning 13 10
+#pragma warning 14 10
+#pragma warning 367 10
+#pragma warning 379 10
+#pragma warning 726 10
+#pragma warning 836 10
+#endif
+
+#ifdef BUILD_FOR_SNAP
+
+#include
+#include
+#include
+
+#elif defined(_WIN32)
+
+#include /* For _MAX_PATH definition */
+#include
+#include
+
+#define WIN32_LEAN_AND_MEAN
+#define NOGDI
+#define NOIME
+#define NOMINMAX
+
+#ifdef __MINGW64_VERSION_MAJOR
+ #undef _WIN32_WINNT
+#endif
+
+#ifndef _WIN32_WINNT
+ /* XXX: Workaround a bug in mingw-w64's headers when NOGDI is set and
+ * _WIN32_WINNT >= 0x0600 */
+ #define _WIN32_WINNT 0x0400
+#endif
+#ifndef STRICT
+ #define STRICT 1
+#endif
+
+#include
+
+/* Disable warnings */
+#if defined(_MSC_VER)
+#pragma warning(disable : 4101)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4761)
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1300
+#pragma comment(linker, "/OPT:NOWIN98")
+#endif
+
+#ifndef WINGDIAPI
+#define WINGDIAPI
+#endif
+
+#elif defined(__OS2__)
+
+#include
+#include
+#include
+#define WINGDIAPI
+
+#else
+
+/* Disable Microsoft-specific keywords */
+#define GLAPIENTRY
+#define WINGDIAPI
+
+#endif
diff --git a/vtm/jni/tessellate/main.c b/vtm/jni/tessellate/main.c
new file mode 100644
index 00000000..0ef62e2d
--- /dev/null
+++ b/vtm/jni/tessellate/main.c
@@ -0,0 +1,54 @@
+#include "tessellate.h"
+#include
+#include
+
+void run_example(const double vertices_array[],
+ const double *contours_array[],
+ int contours_size)
+{
+ double *coordinates_out;
+ int *tris_out;
+ int nverts, ntris, i;
+
+ const double *p = vertices_array;
+ /* const double **contours = contours_array; */
+
+ tessellate(&coordinates_out, &nverts,
+ &tris_out, &ntris,
+ contours_array, contours_array + contours_size);
+
+ for (i=0; i<2 * nverts; ++i) {
+ fprintf(stdout, "%g ", coordinates_out[i]);
+ }
+ fprintf(stdout, "\n");
+ for (i=0; i<3 * ntris; ++i) {
+ fprintf(stdout, "%d ", tris_out[i]);
+ }
+ fprintf(stdout, "\n");
+ free(coordinates_out);
+ if (tris_out)
+ free(tris_out);
+}
+
+int main()
+{
+ double a1[] = { 0, 0, 1, 5, 2, 0, -1, 3, 3, 3 };
+ const double *c1[] = {a1, a1+10};
+ int s1 = 2;
+ run_example(a1, c1, 2);
+ printf("\n");
+ double a2[] = { 0, 0, 3, 0, 3, 3, 0, 3,
+ 1, 1, 2, 1, 2, 2, 1, 2 };
+ const double *c2[] = {a2, a2+8, a2+16};
+ int s2 = 3;
+ run_example(a2, c2, s2);
+ printf("\n");
+
+ double a3[] = { 441, 0, 326, 0, 326, 889, 12, 889, 12, 992, 755, 992, 755, 889, 441, 889 };
+ const double *c3[] = { a3, a3+16 };
+ int s3 = 2;
+ run_example(a3, c3, s3);
+ printf("\n");
+
+ return 0;
+}
diff --git a/vtm/jni/tessellate/memalloc.c b/vtm/jni/tessellate/memalloc.c
new file mode 100644
index 00000000..81879ef7
--- /dev/null
+++ b/vtm/jni/tessellate/memalloc.c
@@ -0,0 +1,55 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "memalloc.h"
+#include "string.h"
+
+int __gl_memInit( size_t maxFast )
+{
+#ifndef NO_MALLOPT
+/* mallopt( M_MXFAST, maxFast );*/
+#ifdef MEMORY_DEBUG
+ mallopt( M_DEBUG, 1 );
+#endif
+#endif
+ return 1;
+}
+
+#ifdef MEMORY_DEBUG
+void *__gl_memAlloc( size_t n )
+{
+ return memset( malloc( n ), 0xa5, n );
+}
+#endif
+
diff --git a/vtm/jni/tessellate/memalloc.h b/vtm/jni/tessellate/memalloc.h
new file mode 100644
index 00000000..c2f969b8
--- /dev/null
+++ b/vtm/jni/tessellate/memalloc.h
@@ -0,0 +1,54 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __memalloc_simple_h_
+#define __memalloc_simple_h_
+
+#include
+
+#define memRealloc realloc
+#define memFree free
+
+#define memInit __gl_memInit
+/*extern void __gl_memInit( size_t );*/
+extern int __gl_memInit( size_t );
+
+#ifndef MEMORY_DEBUG
+#define memAlloc malloc
+#else
+#define memAlloc __gl_memAlloc
+extern void * __gl_memAlloc( size_t );
+#endif
+
+#endif
diff --git a/vtm/jni/tessellate/mesh.c b/vtm/jni/tessellate/mesh.c
new file mode 100644
index 00000000..36cb3a7b
--- /dev/null
+++ b/vtm/jni/tessellate/mesh.c
@@ -0,0 +1,798 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include
+#include
+#include "mesh.h"
+#include "memalloc.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static GLUvertex *allocVertex()
+{
+ return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
+}
+
+static GLUface *allocFace()
+{
+ return (GLUface *)memAlloc( sizeof( GLUface ));
+}
+
+/************************ Utility Routines ************************/
+
+/* Allocate and free half-edges in pairs for efficiency.
+ * The *only* place that should use this fact is allocation/free.
+ */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+/* MakeEdge creates a new pair of half-edges which form their own loop.
+ * No vertex or face structures are allocated, but these must be assigned
+ * before the current edge operation is completed.
+ */
+static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
+{
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUhalfEdge *ePrev;
+ EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
+ if (pair == NULL) return NULL;
+
+ e = &pair->e;
+ eSym = &pair->eSym;
+
+ /* Make sure eNext points to the first edge of the edge pair */
+ if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
+
+ /* Insert in circular doubly-linked list before eNext.
+ * Note that the prev pointer is stored in Sym->next.
+ */
+ ePrev = eNext->Sym->next;
+ eSym->next = ePrev;
+ ePrev->Sym->next = e;
+ e->next = eNext;
+ eNext->Sym->next = eSym;
+
+ e->Sym = eSym;
+ e->Onext = e;
+ e->Lnext = eSym;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->Sym = e;
+ eSym->Onext = eSym;
+ eSym->Lnext = e;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return e;
+}
+
+/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
+ * CS348a notes (see mesh.h). Basically it modifies the mesh so that
+ * a->Onext and b->Onext are exchanged. This can have various effects
+ * depending on whether a and b belong to different face or vertex rings.
+ * For more explanation see __gl_meshSplice() below.
+ */
+static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
+{
+ GLUhalfEdge *aOnext = a->Onext;
+ GLUhalfEdge *bOnext = b->Onext;
+
+ aOnext->Sym->Lnext = b;
+ bOnext->Sym->Lnext = a;
+ a->Onext = bOnext;
+ b->Onext = aOnext;
+}
+
+/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
+ * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
+ * a place to insert the new vertex in the global vertex list. We insert
+ * the new vertex *before* vNext so that algorithms which walk the vertex
+ * list will not see the newly created vertices.
+ */
+static void MakeVertex( GLUvertex *newVertex,
+ GLUhalfEdge *eOrig, GLUvertex *vNext )
+{
+ GLUhalfEdge *e;
+ GLUvertex *vPrev;
+ GLUvertex *vNew = newVertex;
+
+ assert(vNew != NULL);
+
+ /* insert in circular doubly-linked list before vNext */
+ vPrev = vNext->prev;
+ vNew->prev = vPrev;
+ vPrev->next = vNew;
+ vNew->next = vNext;
+ vNext->prev = vNew;
+
+ vNew->anEdge = eOrig;
+ vNew->data = NULL;
+ /* leave coords, s, t undefined */
+
+ /* fix other edges on this vertex loop */
+ e = eOrig;
+ do {
+ e->Org = vNew;
+ e = e->Onext;
+ } while( e != eOrig );
+}
+
+/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
+ * face of all edges in the face loop to which eOrig belongs. "fNext" gives
+ * a place to insert the new face in the global face list. We insert
+ * the new face *before* fNext so that algorithms which walk the face
+ * list will not see the newly created faces.
+ */
+static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
+{
+ GLUhalfEdge *e;
+ GLUface *fPrev;
+ GLUface *fNew = newFace;
+
+ assert(fNew != NULL);
+
+ /* insert in circular doubly-linked list before fNext */
+ fPrev = fNext->prev;
+ fNew->prev = fPrev;
+ fPrev->next = fNew;
+ fNew->next = fNext;
+ fNext->prev = fNew;
+
+ fNew->anEdge = eOrig;
+ fNew->data = NULL;
+ fNew->trail = NULL;
+ fNew->marked = FALSE;
+
+ /* The new face is marked "inside" if the old one was. This is a
+ * convenience for the common case where a face has been split in two.
+ */
+ fNew->inside = fNext->inside;
+
+ /* fix other edges on this face loop */
+ e = eOrig;
+ do {
+ e->Lface = fNew;
+ e = e->Lnext;
+ } while( e != eOrig );
+}
+
+/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
+ * and removes from the global edge list.
+ */
+static void KillEdge( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *ePrev, *eNext;
+
+ /* Half-edges are allocated in pairs, see EdgePair above */
+ if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
+
+ /* delete from circular doubly-linked list */
+ eNext = eDel->next;
+ ePrev = eDel->Sym->next;
+ eNext->Sym->next = ePrev;
+ ePrev->Sym->next = eNext;
+
+ memFree( eDel );
+}
+
+
+/* KillVertex( vDel ) destroys a vertex and removes it from the global
+ * vertex list. It updates the vertex loop to point to a given new vertex.
+ */
+static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
+{
+ GLUhalfEdge *e, *eStart = vDel->anEdge;
+ GLUvertex *vPrev, *vNext;
+
+ /* change the origin of all affected edges */
+ e = eStart;
+ do {
+ e->Org = newOrg;
+ e = e->Onext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ vPrev = vDel->prev;
+ vNext = vDel->next;
+ vNext->prev = vPrev;
+ vPrev->next = vNext;
+
+ memFree( vDel );
+}
+
+/* KillFace( fDel ) destroys a face and removes it from the global face
+ * list. It updates the face loop to point to a given new face.
+ */
+static void KillFace( GLUface *fDel, GLUface *newLface )
+{
+ GLUhalfEdge *e, *eStart = fDel->anEdge;
+ GLUface *fPrev, *fNext;
+
+ /* change the left face of all affected edges */
+ e = eStart;
+ do {
+ e->Lface = newLface;
+ e = e->Lnext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fDel->prev;
+ fNext = fDel->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fDel );
+}
+
+
+/****************** Basic Edge Operations **********************/
+
+/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
+ * The loop consists of the two new half-edges.
+ */
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
+{
+ GLUvertex *newVertex1= allocVertex();
+ GLUvertex *newVertex2= allocVertex();
+ GLUface *newFace= allocFace();
+ GLUhalfEdge *e;
+
+ /* if any one is null then all get freed */
+ if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
+ if (newVertex1 != NULL) memFree(newVertex1);
+ if (newVertex2 != NULL) memFree(newVertex2);
+ if (newFace != NULL) memFree(newFace);
+ return NULL;
+ }
+
+ e = MakeEdge( &mesh->eHead );
+ if (e == NULL) {
+ memFree(newVertex1);
+ memFree(newVertex2);
+ memFree(newFace);
+ return NULL;
+ }
+
+ MakeVertex( newVertex1, e, &mesh->vHead );
+ MakeVertex( newVertex2, e->Sym, &mesh->vHead );
+ MakeFace( newFace, e, &mesh->fHead );
+ return e;
+}
+
+
+/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * Some special cases:
+ * If eDst == eOrg, the operation has no effect.
+ * If eDst == eOrg->Lnext, the new face will have a single edge.
+ * If eDst == eOrg->Lprev, the old face will have a single edge.
+ * If eDst == eOrg->Onext, the new vertex will have a single edge.
+ * If eDst == eOrg->Oprev, the old vertex will have a single edge.
+ */
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ int joiningLoops = FALSE;
+ int joiningVertices = FALSE;
+
+ if( eOrg == eDst ) return 1;
+
+ if( eDst->Org != eOrg->Org ) {
+ /* We are merging two disjoint vertices -- destroy eDst->Org */
+ joiningVertices = TRUE;
+ KillVertex( eDst->Org, eOrg->Org );
+ }
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Change the edge structure */
+ Splice( eDst, eOrg );
+
+ if( ! joiningVertices ) {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return 0;
+
+ /* We split one vertex into two -- the new vertex is eDst->Org.
+ * Make sure the old vertex points to a valid half-edge.
+ */
+ MakeVertex( newVertex, eDst, eOrg->Org );
+ eOrg->Org->anEdge = eOrg;
+ }
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We split one loop into two -- the new loop is eDst->Lface.
+ * Make sure the old face points to a valid half-edge.
+ */
+ MakeFace( newFace, eDst, eOrg->Lface );
+ eOrg->Lface->anEdge = eOrg;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * This function could be implemented as two calls to __gl_meshSplice
+ * plus a few calls to memFree, but this would allocate and delete
+ * unnecessary vertices and faces.
+ */
+int __gl_meshDelete( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *eDelSym = eDel->Sym;
+ int joiningLoops = FALSE;
+
+ /* First step: disconnect the origin vertex eDel->Org. We make all
+ * changes to get a consistent mesh in this "intermediate" state.
+ */
+ if( eDel->Lface != eDel->Rface ) {
+ /* We are joining two loops into one -- remove the left face */
+ joiningLoops = TRUE;
+ KillFace( eDel->Lface, eDel->Rface );
+ }
+
+ if( eDel->Onext == eDel ) {
+ KillVertex( eDel->Org, NULL );
+ } else {
+ /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
+ eDel->Rface->anEdge = eDel->Oprev;
+ eDel->Org->anEdge = eDel->Onext;
+
+ Splice( eDel, eDel->Oprev );
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We are splitting one loop into two -- create a new loop for eDel. */
+ MakeFace( newFace, eDel, eDel->Lface );
+ }
+ }
+
+ /* Claim: the mesh is now in a consistent state, except that eDel->Org
+ * may have been deleted. Now we disconnect eDel->Dst.
+ */
+ if( eDelSym->Onext == eDelSym ) {
+ KillVertex( eDelSym->Org, NULL );
+ KillFace( eDelSym->Lface, NULL );
+ } else {
+ /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
+ eDel->Lface->anEdge = eDelSym->Oprev;
+ eDelSym->Org->anEdge = eDelSym->Onext;
+ Splice( eDelSym, eDelSym->Oprev );
+ }
+
+ /* Any isolated vertices or faces have already been freed. */
+ KillEdge( eDel );
+
+ return 1;
+}
+
+
+/******************** Other Edge Operations **********************/
+
+/* All these routines can be implemented with the basic edge
+ * operations above. They are provided for convenience and efficiency.
+ */
+
+
+/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNewSym;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return NULL;
+
+ MakeVertex( newVertex, eNewSym, eNew->Org );
+ }
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ return eNew;
+}
+
+
+/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
+ if (tempHalfEdge == NULL) return NULL;
+
+ eNew = tempHalfEdge->Sym;
+
+ /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
+ Splice( eOrg->Sym, eOrg->Sym->Oprev );
+ Splice( eOrg->Sym, eNew );
+
+ /* Set the vertex and face information */
+ eOrg->Dst = eNew->Org;
+ eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
+ eNew->Rface = eOrg->Rface;
+ eNew->winding = eOrg->winding; /* copy old winding information */
+ eNew->Sym->winding = eOrg->Sym->winding;
+
+ return eNew;
+}
+
+
+/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * If (eOrg == eDst), the new face will have only two edges.
+ * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
+ * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
+ */
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ GLUhalfEdge *eNewSym;
+ int joiningLoops = FALSE;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+ Splice( eNewSym, eDst );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ eNewSym->Org = eDst->Org;
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ /* Make sure the old face points to a valid half-edge */
+ eOrg->Lface->anEdge = eNewSym;
+
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return NULL;
+
+ /* We split one loop into two -- the new loop is eNew->Lface */
+ MakeFace( newFace, eNew, eOrg->Lface );
+ }
+ return eNew;
+}
+
+
+/******************** Other Operations **********************/
+
+/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ */
+void __gl_meshZapFace( GLUface *fZap )
+{
+ GLUhalfEdge *eStart = fZap->anEdge;
+ GLUhalfEdge *e, *eNext, *eSym;
+ GLUface *fPrev, *fNext;
+
+ /* walk around face, deleting edges whose right face is also NULL */
+ eNext = eStart->Lnext;
+ do {
+ e = eNext;
+ eNext = e->Lnext;
+
+ e->Lface = NULL;
+ if( e->Rface == NULL ) {
+ /* delete the edge -- see __gl_MeshDelete above */
+
+ if( e->Onext == e ) {
+ KillVertex( e->Org, NULL );
+ } else {
+ /* Make sure that e->Org points to a valid half-edge */
+ e->Org->anEdge = e->Onext;
+ Splice( e, e->Oprev );
+ }
+ eSym = e->Sym;
+ if( eSym->Onext == eSym ) {
+ KillVertex( eSym->Org, NULL );
+ } else {
+ /* Make sure that eSym->Org points to a valid half-edge */
+ eSym->Org->anEdge = eSym->Onext;
+ Splice( eSym, eSym->Oprev );
+ }
+ KillEdge( e );
+ }
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fZap->prev;
+ fNext = fZap->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fZap );
+}
+
+
+/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ */
+GLUmesh *__gl_meshNewMesh( void )
+{
+ GLUvertex *v;
+ GLUface *f;
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
+ if (mesh == NULL) {
+ return NULL;
+ }
+
+ v = &mesh->vHead;
+ f = &mesh->fHead;
+ e = &mesh->eHead;
+ eSym = &mesh->eHeadSym;
+
+ v->next = v->prev = v;
+ v->anEdge = NULL;
+ v->data = NULL;
+
+ f->next = f->prev = f;
+ f->anEdge = NULL;
+ f->data = NULL;
+ f->trail = NULL;
+ f->marked = FALSE;
+ f->inside = FALSE;
+
+ e->next = e;
+ e->Sym = eSym;
+ e->Onext = NULL;
+ e->Lnext = NULL;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->next = eSym;
+ eSym->Sym = e;
+ eSym->Onext = NULL;
+ eSym->Lnext = NULL;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return mesh;
+}
+
+
+/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ */
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
+{
+ GLUface *f1 = &mesh1->fHead;
+ GLUvertex *v1 = &mesh1->vHead;
+ GLUhalfEdge *e1 = &mesh1->eHead;
+ GLUface *f2 = &mesh2->fHead;
+ GLUvertex *v2 = &mesh2->vHead;
+ GLUhalfEdge *e2 = &mesh2->eHead;
+
+ /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
+ if( f2->next != f2 ) {
+ f1->prev->next = f2->next;
+ f2->next->prev = f1->prev;
+ f2->prev->next = f1;
+ f1->prev = f2->prev;
+ }
+
+ if( v2->next != v2 ) {
+ v1->prev->next = v2->next;
+ v2->next->prev = v1->prev;
+ v2->prev->next = v1;
+ v1->prev = v2->prev;
+ }
+
+ if( e2->next != e2 ) {
+ e1->Sym->next->Sym->next = e2->next;
+ e2->next->Sym->next = e1->Sym->next;
+ e2->Sym->next->Sym->next = e1;
+ e1->Sym->next = e2->Sym->next;
+ }
+
+ memFree( mesh2 );
+ return mesh1;
+}
+
+
+#ifdef DELETE_BY_ZAPPING
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+
+ while( fHead->next != fHead ) {
+ __gl_meshZapFace( fHead->next );
+ }
+ assert( mesh->vHead.next == &mesh->vHead );
+
+ memFree( mesh );
+}
+
+#else
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *f, *fNext;
+ GLUvertex *v, *vNext;
+ GLUhalfEdge *e, *eNext;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ memFree( f );
+ }
+
+ for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
+ vNext = v->next;
+ memFree( v );
+ }
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ /* One call frees both e and e->Sym (see EdgePair above) */
+ eNext = e->next;
+ memFree( e );
+ }
+
+ memFree( mesh );
+}
+
+#endif
+
+#ifndef NDEBUG
+
+/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+void __gl_meshCheckMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+ GLUvertex *vHead = &mesh->vHead;
+ GLUhalfEdge *eHead = &mesh->eHead;
+ GLUface *f, *fPrev;
+ GLUvertex *v, *vPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ fPrev = fHead;
+ for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
+ assert( f->prev == fPrev );
+ e = f->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Lface == f );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
+
+ vPrev = vHead;
+ for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
+ assert( v->prev == vPrev );
+ e = v->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Org == v );
+ e = e->Onext;
+ } while( e != v->anEdge );
+ }
+ assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
+
+ ePrev = eHead;
+ for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
+ assert( e->Sym->next == ePrev->Sym );
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Org != NULL );
+ assert( e->Dst != NULL );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ }
+ assert( e->Sym->next == ePrev->Sym
+ && e->Sym == &mesh->eHeadSym
+ && e->Sym->Sym == e
+ && e->Org == NULL && e->Dst == NULL
+ && e->Lface == NULL && e->Rface == NULL );
+}
+
+#endif
diff --git a/vtm/jni/tessellate/mesh.h b/vtm/jni/tessellate/mesh.h
new file mode 100644
index 00000000..20a4b2b9
--- /dev/null
+++ b/vtm/jni/tessellate/mesh.h
@@ -0,0 +1,266 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __mesh_h_
+#define __mesh_h_
+
+#include "glu.h"
+
+typedef struct GLUmesh GLUmesh;
+
+typedef struct GLUvertex GLUvertex;
+typedef struct GLUface GLUface;
+typedef struct GLUhalfEdge GLUhalfEdge;
+
+typedef struct ActiveRegion ActiveRegion; /* Internal data */
+
+/* The mesh structure is similar in spirit, notation, and operations
+ * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
+ * for the manipulation of general subdivisions and the computation of
+ * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
+ * For a simplified description, see the course notes for CS348a,
+ * "Mathematical Foundations of Computer Graphics", available at the
+ * Stanford bookstore (and taught during the fall quarter).
+ * The implementation also borrows a tiny subset of the graph-based approach
+ * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
+ * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
+ *
+ * The fundamental data structure is the "half-edge". Two half-edges
+ * go together to make an edge, but they point in opposite directions.
+ * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
+ * its origin vertex (Org), the face on its left side (Lface), and the
+ * adjacent half-edges in the CCW direction around the origin vertex
+ * (Onext) and around the left face (Lnext). There is also a "next"
+ * pointer for the global edge list (see below).
+ *
+ * The notation used for mesh navigation:
+ * Sym = the mate of a half-edge (same edge, but opposite direction)
+ * Onext = edge CCW around origin vertex (keep same origin)
+ * Dnext = edge CCW around destination vertex (keep same dest)
+ * Lnext = edge CCW around left face (dest becomes new origin)
+ * Rnext = edge CCW around right face (origin becomes new dest)
+ *
+ * "prev" means to substitute CW for CCW in the definitions above.
+ *
+ * The mesh keeps global lists of all vertices, faces, and edges,
+ * stored as doubly-linked circular lists with a dummy header node.
+ * The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
+ *
+ * The circular edge list is special; since half-edges always occur
+ * in pairs (e and e->Sym), each half-edge stores a pointer in only
+ * one direction. Starting at eHead and following the e->next pointers
+ * will visit each *edge* once (ie. e or e->Sym, but not both).
+ * e->Sym stores a pointer in the opposite direction, thus it is
+ * always true that e->Sym->next->Sym->next == e.
+ *
+ * Each vertex has a pointer to next and previous vertices in the
+ * circular list, and a pointer to a half-edge with this vertex as
+ * the origin (NULL if this is the dummy header). There is also a
+ * field "data" for client data.
+ *
+ * Each face has a pointer to the next and previous faces in the
+ * circular list, and a pointer to a half-edge with this face as
+ * the left face (NULL if this is the dummy header). There is also
+ * a field "data" for client data.
+ *
+ * Note that what we call a "face" is really a loop; faces may consist
+ * of more than one loop (ie. not simply connected), but there is no
+ * record of this in the data structure. The mesh may consist of
+ * several disconnected regions, so it may not be possible to visit
+ * the entire mesh by starting at a half-edge and traversing the edge
+ * structure.
+ *
+ * The mesh does NOT support isolated vertices; a vertex is deleted along
+ * with its last edge. Similarly when two faces are merged, one of the
+ * faces is deleted (see __gl_meshDelete below). For mesh operations,
+ * all face (loop) and vertex pointers must not be NULL. However, once
+ * mesh manipulation is finished, __gl_MeshZapFace can be used to delete
+ * faces of the mesh, one at a time. All external faces can be "zapped"
+ * before the mesh is returned to the client; then a NULL face indicates
+ * a region which is not part of the output polygon.
+ */
+
+struct GLUvertex {
+ GLUvertex *next; /* next vertex (never NULL) */
+ GLUvertex *prev; /* previous vertex (never NULL) */
+ GLUhalfEdge *anEdge; /* a half-edge with this origin */
+ void *data; /* client's data */
+
+ /* Internal data (keep hidden) */
+ GLdouble coords[3]; /* vertex location in 3D */
+ GLdouble s, t; /* projection onto the sweep plane */
+ long pqHandle; /* to allow deletion from priority queue */
+};
+
+struct GLUface {
+ GLUface *next; /* next face (never NULL) */
+ GLUface *prev; /* previous face (never NULL) */
+ GLUhalfEdge *anEdge; /* a half edge with this left face */
+ void *data; /* room for client's data */
+
+ /* Internal data (keep hidden) */
+ GLUface *trail; /* "stack" for conversion to strips */
+ GLboolean marked; /* flag for conversion to strips */
+ GLboolean inside; /* this face is in the polygon interior */
+};
+
+struct GLUhalfEdge {
+ GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
+ GLUhalfEdge *Sym; /* same edge, opposite direction */
+ GLUhalfEdge *Onext; /* next edge CCW around origin */
+ GLUhalfEdge *Lnext; /* next edge CCW around left face */
+ GLUvertex *Org; /* origin vertex (Overtex too long) */
+ GLUface *Lface; /* left face */
+
+ /* Internal data (keep hidden) */
+ ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
+ int winding; /* change in winding number when crossing
+ from the right face to the left face */
+};
+
+#define Rface Sym->Lface
+#define Dst Sym->Org
+
+#define Oprev Sym->Lnext
+#define Lprev Onext->Sym
+#define Dprev Lnext->Sym
+#define Rprev Sym->Onext
+#define Dnext Rprev->Sym /* 3 pointers */
+#define Rnext Oprev->Sym /* 3 pointers */
+
+
+struct GLUmesh {
+ GLUvertex vHead; /* dummy header for vertex list */
+ GLUface fHead; /* dummy header for face list */
+ GLUhalfEdge eHead; /* dummy header for edge list */
+ GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
+};
+
+/* The mesh operations below have three motivations: completeness,
+ * convenience, and efficiency. The basic mesh operations are MakeEdge,
+ * Splice, and Delete. All the other edge operations can be implemented
+ * in terms of these. The other operations are provided for convenience
+ * and/or efficiency.
+ *
+ * When a face is split or a vertex is added, they are inserted into the
+ * global list *before* the existing vertex or face (ie. e->Org or e->Lface).
+ * This makes it easier to process all vertices or faces in the global lists
+ * without worrying about processing the same data twice. As a convenience,
+ * when a face is split, the "inside" flag is copied from the old face.
+ * Other internal data (v->data, v->activeRegion, f->data, f->marked,
+ * f->trail, e->winding) is set to zero.
+ *
+ * ********************** Basic Edge Operations **************************
+ *
+ * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
+ * The loop (face) consists of the two new half-edges.
+ *
+ * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * ********************** Other Edge Operations **************************
+ *
+ * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * ************************ Other Operations *****************************
+ *
+ * __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ *
+ * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ *
+ * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ *
+ * __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ *
+ * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh );
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+int __gl_meshDelete( GLUhalfEdge *eDel );
+
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+
+GLUmesh *__gl_meshNewMesh( void );
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
+void __gl_meshDeleteMesh( GLUmesh *mesh );
+void __gl_meshZapFace( GLUface *fZap );
+
+#ifdef NDEBUG
+#define __gl_meshCheckMesh( mesh )
+#else
+void __gl_meshCheckMesh( GLUmesh *mesh );
+#endif
+
+#endif
diff --git a/vtm/jni/tessellate/normal.c b/vtm/jni/tessellate/normal.c
new file mode 100644
index 00000000..9a3bd43d
--- /dev/null
+++ b/vtm/jni/tessellate/normal.c
@@ -0,0 +1,257 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include "mesh.h"
+#include "tess.h"
+#include "normal.h"
+#include
+#include
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
+
+#if 0
+static void Normalize( GLdouble v[3] )
+{
+ GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+
+ assert( len > 0 );
+ len = sqrt( len );
+ v[0] /= len;
+ v[1] /= len;
+ v[2] /= len;
+}
+#endif
+
+#undef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+static int LongAxis( GLdouble v[3] )
+{
+ int i = 0;
+
+ if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
+ if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
+ return i;
+}
+
+static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
+{
+ GLUvertex *v, *v1, *v2;
+ GLdouble c, tLen2, maxLen2;
+ GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
+ GLUvertex *maxVert[3], *minVert[3];
+ GLUvertex *vHead = &tess->mesh->vHead;
+ int i;
+
+ maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
+ minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
+
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ for( i = 0; i < 3; ++i ) {
+ c = v->coords[i];
+ if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
+ if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
+ }
+ }
+
+ /* Find two vertices separated by at least 1/sqrt(3) of the maximum
+ * distance between any two vertices
+ */
+ i = 0;
+ if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
+ if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
+ if( minVal[i] >= maxVal[i] ) {
+ /* All vertices are the same -- normal doesn't matter */
+ norm[0] = 0; norm[1] = 0; norm[2] = 1;
+ return;
+ }
+
+ /* Look for a third vertex which forms the triangle with maximum area
+ * (Length of normal == twice the triangle area)
+ */
+ maxLen2 = 0;
+ v1 = minVert[i];
+ v2 = maxVert[i];
+ d1[0] = v1->coords[0] - v2->coords[0];
+ d1[1] = v1->coords[1] - v2->coords[1];
+ d1[2] = v1->coords[2] - v2->coords[2];
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ d2[0] = v->coords[0] - v2->coords[0];
+ d2[1] = v->coords[1] - v2->coords[1];
+ d2[2] = v->coords[2] - v2->coords[2];
+ tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
+ tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
+ tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
+ tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
+ if( tLen2 > maxLen2 ) {
+ maxLen2 = tLen2;
+ norm[0] = tNorm[0];
+ norm[1] = tNorm[1];
+ norm[2] = tNorm[2];
+ }
+ }
+
+ if( maxLen2 <= 0 ) {
+ /* All points lie on a single line -- any decent normal will do */
+ norm[0] = norm[1] = norm[2] = 0;
+ norm[LongAxis(d1)] = 1;
+ }
+}
+
+
+static void CheckOrientation( GLUtesselator *tess )
+{
+ GLdouble area;
+ GLUface *f, *fHead = &tess->mesh->fHead;
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLUhalfEdge *e;
+
+ /* When we compute the normal automatically, we choose the orientation
+ * so that the sum of the signed areas of all contours is non-negative.
+ */
+ area = 0;
+ for( f = fHead->next; f != fHead; f = f->next ) {
+ e = f->anEdge;
+ if( e->winding <= 0 ) continue;
+ do {
+ area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ if( area < 0 ) {
+ /* Reverse the orientation by flipping all the t-coordinates */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->t = - v->t;
+ }
+ tess->tUnit[0] = - tess->tUnit[0];
+ tess->tUnit[1] = - tess->tUnit[1];
+ tess->tUnit[2] = - tess->tUnit[2];
+ }
+}
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#include
+extern int RandomSweep;
+#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
+#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
+#else
+#if defined(SLANTED_SWEEP)
+/* The "feature merging" is not intended to be complete. There are
+ * special cases where edges are nearly parallel to the sweep line
+ * which are not implemented. The algorithm should still behave
+ * robustly (ie. produce a reasonable tesselation) in the presence
+ * of such edges, however it may miss features which could have been
+ * merged. We could minimize this effect by choosing the sweep line
+ * direction to be something unusual (ie. not parallel to one of the
+ * coordinate axes).
+ */
+#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
+#define S_UNIT_Y 0.86052074622010633
+#else
+#define S_UNIT_X 1.0
+#define S_UNIT_Y 0.0
+#endif
+#endif
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess )
+{
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLdouble norm[3];
+ GLdouble *sUnit, *tUnit;
+ int i, computedNormal = FALSE;
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm );
+ computedNormal = TRUE;
+ }
+ sUnit = tess->sUnit;
+ tUnit = tess->tUnit;
+ i = LongAxis( norm );
+
+#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
+ /* Choose the initial sUnit vector to be approximately perpendicular
+ * to the normal.
+ */
+ Normalize( norm );
+
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ /* Now make it exactly perpendicular */
+ w = Dot( sUnit, norm );
+ sUnit[0] -= w * norm[0];
+ sUnit[1] -= w * norm[1];
+ sUnit[2] -= w * norm[2];
+ Normalize( sUnit );
+
+ /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
+ tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
+ tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
+ tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
+ Normalize( tUnit );
+#else
+ /* Project perpendicular to a coordinate axis -- better numerically */
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ tUnit[i] = 0;
+ tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
+ tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
+#endif
+
+ /* Project the vertices onto the sweep plane */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->s = Dot( v->coords, sUnit );
+ v->t = Dot( v->coords, tUnit );
+ }
+ if( computedNormal ) {
+ CheckOrientation( tess );
+ }
+}
diff --git a/vtm/jni/tessellate/normal.h b/vtm/jni/tessellate/normal.h
new file mode 100644
index 00000000..c376ca44
--- /dev/null
+++ b/vtm/jni/tessellate/normal.h
@@ -0,0 +1,45 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __normal_h_
+#define __normal_h_
+
+#include "tess.h"
+
+/* __gl_projectPolygon( tess ) determines the polygon normal
+ * and project vertices onto the plane of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess );
+
+#endif
diff --git a/vtm/jni/tessellate/priorityq-heap.c b/vtm/jni/tessellate/priorityq-heap.c
new file mode 100644
index 00000000..898c561b
--- /dev/null
+++ b/vtm/jni/tessellate/priorityq-heap.c
@@ -0,0 +1,257 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include
+#include
+#include
+#include "priorityq-heap.h"
+#include "memalloc.h"
+
+#define INIT_SIZE 32
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#define LEQ(x,y) (*pq->leq)(x,y)
+#else
+/* Violates modularity, but a little faster */
+#include "geom.h"
+#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
+#endif
+
+/* really __gl_pqHeapNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
+ if (pq->nodes == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
+ if (pq->handles == NULL) {
+ memFree(pq->nodes);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->initialized = FALSE;
+ pq->freeList = 0;
+ pq->leq = leq;
+
+ pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
+ pq->handles[1].key = NULL;
+ return pq;
+}
+
+/* really __gl_pqHeapDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ memFree( pq->handles );
+ memFree( pq->nodes );
+ memFree( pq );
+}
+
+
+static void FloatDown( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hChild;
+ long child;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ child = curr << 1;
+ if( child < pq->size && LEQ( h[n[child+1].handle].key,
+ h[n[child].handle].key )) {
+ ++child;
+ }
+
+ assert(child <= pq->max);
+
+ hChild = n[child].handle;
+ if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hChild;
+ h[hChild].node = curr;
+ curr = child;
+ }
+}
+
+
+static void FloatUp( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hParent;
+ long parent;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ parent = curr >> 1;
+ hParent = n[parent].handle;
+ if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hParent;
+ h[hParent].node = curr;
+ curr = parent;
+ }
+}
+
+/* really __gl_pqHeapInit */
+void pqInit( PriorityQ *pq )
+{
+ long i;
+
+ /* This method of building a heap is O(n), rather than O(n lg n). */
+
+ for( i = pq->size; i >= 1; --i ) {
+ FloatDown( pq, i );
+ }
+ pq->initialized = TRUE;
+}
+
+/* really __gl_pqHeapInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+ PQhandle free_handle;
+
+ curr = ++ pq->size;
+ if( (curr*2) > pq->max ) {
+ PQnode *saveNodes= pq->nodes;
+ PQhandleElem *saveHandles= pq->handles;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->nodes = (PQnode *)memRealloc( pq->nodes,
+ (size_t)
+ ((pq->max + 1) * sizeof( pq->nodes[0] )));
+ if (pq->nodes == NULL) {
+ pq->nodes = saveNodes; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ pq->handles = (PQhandleElem *)memRealloc( pq->handles,
+ (size_t)
+ ((pq->max + 1) *
+ sizeof( pq->handles[0] )));
+ if (pq->handles == NULL) {
+ pq->handles = saveHandles; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+
+ if( pq->freeList == 0 ) {
+ free_handle = curr;
+ } else {
+ free_handle = pq->freeList;
+ pq->freeList = pq->handles[free_handle].node;
+ }
+
+ pq->nodes[curr].handle = free_handle;
+ pq->handles[free_handle].node = curr;
+ pq->handles[free_handle].key = keyNew;
+
+ if( pq->initialized ) {
+ FloatUp( pq, curr );
+ }
+ assert(free_handle != LONG_MAX);
+ return free_handle;
+}
+
+/* really __gl_pqHeapExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hMin = n[1].handle;
+ PQkey min = h[hMin].key;
+
+ if( pq->size > 0 ) {
+ n[1].handle = n[pq->size].handle;
+ h[n[1].handle].node = 1;
+
+ h[hMin].key = NULL;
+ h[hMin].node = pq->freeList;
+ pq->freeList = hMin;
+
+ if( -- pq->size > 0 ) {
+ FloatDown( pq, 1 );
+ }
+ }
+ return min;
+}
+
+/* really __gl_pqHeapDelete */
+void pqDelete( PriorityQ *pq, PQhandle hCurr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ long curr;
+
+ assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
+
+ curr = h[hCurr].node;
+ n[curr].handle = n[pq->size].handle;
+ h[n[curr].handle].node = curr;
+
+ if( curr <= -- pq->size ) {
+ if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
+ FloatDown( pq, curr );
+ } else {
+ FloatUp( pq, curr );
+ }
+ }
+ h[hCurr].key = NULL;
+ h[hCurr].node = pq->freeList;
+ pq->freeList = hCurr;
+}
diff --git a/vtm/jni/tessellate/priorityq-heap.h b/vtm/jni/tessellate/priorityq-heap.h
new file mode 100644
index 00000000..dc9aaef8
--- /dev/null
+++ b/vtm/jni/tessellate/priorityq-heap.h
@@ -0,0 +1,107 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_heap_h_
+#define __priorityq_heap_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQHeapKey
+#define PQhandle PQHeapHandle
+#define PriorityQ PriorityQHeap
+
+#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqHeapInit(pq)
+#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key)
+#define pqMinimum(pq) __gl_pqHeapMinimum(pq)
+#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef void *PQkey;
+typedef long PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+typedef struct { PQhandle handle; } PQnode;
+typedef struct { PQkey key; PQhandle node; } PQhandleElem;
+
+struct PriorityQ {
+ PQnode *nodes;
+ PQhandleElem *handles;
+ long size, max;
+ PQhandle freeList;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+void pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+
+#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
+#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
+
+#endif
diff --git a/vtm/jni/tessellate/priorityq-sort.h b/vtm/jni/tessellate/priorityq-sort.h
new file mode 100644
index 00000000..746cf5fa
--- /dev/null
+++ b/vtm/jni/tessellate/priorityq-sort.h
@@ -0,0 +1,117 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/vtm/jni/tessellate/priorityq.c b/vtm/jni/tessellate/priorityq.c
new file mode 100644
index 00000000..c6b99cce
--- /dev/null
+++ b/vtm/jni/tessellate/priorityq.c
@@ -0,0 +1,260 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include
+#include
+#include /* LONG_MAX */
+#include "memalloc.h"
+
+/* Include all the code for the regular heap-based queue here. */
+
+#include "priorityq-heap.c"
+
+/* Now redefine all the function names to map to their "Sort" versions. */
+
+#include "priorityq-sort.h"
+
+/* really __gl_pqSortNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->heap = __gl_pqHeapNewPriorityQ( leq );
+ if (pq->heap == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
+ if (pq->keys == NULL) {
+ __gl_pqHeapDeletePriorityQ(pq->heap);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->initialized = FALSE;
+ pq->leq = leq;
+ return pq;
+}
+
+/* really __gl_pqSortDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ assert(pq != NULL);
+ if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
+ if (pq->order != NULL) memFree( pq->order );
+ if (pq->keys != NULL) memFree( pq->keys );
+ memFree( pq );
+}
+
+
+#define LT(x,y) (! LEQ(y,x))
+#define GT(x,y) (! LEQ(x,y))
+#define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
+
+/* really __gl_pqSortInit */
+int pqInit( PriorityQ *pq )
+{
+ PQkey **p, **r, **i, **j, *piv;
+ struct { PQkey **p, **r; } Stack[50], *top = Stack;
+ unsigned long seed = 2016473283;
+
+ /* Create an array of indirect pointers to the keys, so that we
+ * the handles we have returned are still valid.
+ */
+/*
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ (pq->size * sizeof(pq->order[0])) );
+*/
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ ((pq->size+1) * sizeof(pq->order[0])) );
+/* the previous line is a patch to compensate for the fact that IBM */
+/* machines return a null on a malloc of zero bytes (unlike SGI), */
+/* so we have to put in this defense to guard against a memory */
+/* fault four lines down. from fossum@austin.ibm.com. */
+ if (pq->order == NULL) return 0;
+
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
+ *i = piv;
+ }
+
+ /* Sort the indirect pointers in descending order,
+ * using randomized Quicksort
+ */
+ top->p = p; top->r = r; ++top;
+ while( --top >= Stack ) {
+ p = top->p;
+ r = top->r;
+ while( r > p + 10 ) {
+ seed = seed * 1539415821 + 1;
+ i = p + seed % (r - p + 1);
+ piv = *i;
+ *i = *p;
+ *p = piv;
+ i = p - 1;
+ j = r + 1;
+ do {
+ do { ++i; } while( GT( **i, *piv ));
+ do { --j; } while( LT( **j, *piv ));
+ Swap( i, j );
+ } while( i < j );
+ Swap( i, j ); /* Undo last swap */
+ if( i - p < r - j ) {
+ top->p = j+1; top->r = r; ++top;
+ r = i-1;
+ } else {
+ top->p = p; top->r = i-1; ++top;
+ p = j+1;
+ }
+ }
+ /* Insertion sort small lists */
+ for( i = p+1; i <= r; ++i ) {
+ piv = *i;
+ for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
+ *j = *(j-1);
+ }
+ *j = piv;
+ }
+ }
+ pq->max = pq->size;
+ pq->initialized = TRUE;
+ __gl_pqHeapInit( pq->heap ); /* always succeeds */
+
+#ifndef NDEBUG
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( i = p; i < r; ++i ) {
+ assert( LEQ( **(i+1), **i ));
+ }
+#endif
+
+ return 1;
+}
+
+/* really __gl_pqSortInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+
+ if( pq->initialized ) {
+ return __gl_pqHeapInsert( pq->heap, keyNew );
+ }
+ curr = pq->size;
+ if( ++ pq->size >= pq->max ) {
+ PQkey *saveKey= pq->keys;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->keys = (PQHeapKey *)memRealloc( pq->keys,
+ (size_t)
+ (pq->max * sizeof( pq->keys[0] )));
+ if (pq->keys == NULL) {
+ pq->keys = saveKey; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+ assert(curr != LONG_MAX);
+ pq->keys[curr] = keyNew;
+
+ /* Negative handles index the sorted array. */
+ return -(curr+1);
+}
+
+/* really __gl_pqSortExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ }
+ do {
+ -- pq->size;
+ } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
+ return sortMin;
+}
+
+/* really __gl_pqSortMinimum */
+PQkey pqMinimum( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapMinimum( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return heapMin;
+ }
+ }
+ return sortMin;
+}
+
+/* really __gl_pqSortIsEmpty */
+int pqIsEmpty( PriorityQ *pq )
+{
+ return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
+}
+
+/* really __gl_pqSortDelete */
+void pqDelete( PriorityQ *pq, PQhandle curr )
+{
+ if( curr >= 0 ) {
+ __gl_pqHeapDelete( pq->heap, curr );
+ return;
+ }
+ curr = -(curr+1);
+ assert( curr < pq->max && pq->keys[curr] != NULL );
+
+ pq->keys[curr] = NULL;
+ while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
+ -- pq->size;
+ }
+}
diff --git a/vtm/jni/tessellate/priorityq.h b/vtm/jni/tessellate/priorityq.h
new file mode 100644
index 00000000..746cf5fa
--- /dev/null
+++ b/vtm/jni/tessellate/priorityq.h
@@ -0,0 +1,117 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/vtm/jni/tessellate/render.c b/vtm/jni/tessellate/render.c
new file mode 100644
index 00000000..bca836f0
--- /dev/null
+++ b/vtm/jni/tessellate/render.c
@@ -0,0 +1,502 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include
+#include
+#include "mesh.h"
+#include "tess.h"
+#include "render.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* This structure remembers the information we need about a primitive
+ * to be able to render it later, once we have determined which
+ * primitive is able to use the most triangles.
+ */
+struct FaceCount {
+ long size; /* number of triangles used */
+ GLUhalfEdge *eStart; /* edge where this primitive starts */
+ void (*render)(GLUtesselator *, GLUhalfEdge *, long);
+ /* routine to render this primitive */
+};
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
+ long size );
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
+
+
+
+/************************ Strips and Fans decomposition ******************/
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+
+ /* Make a list of separate triangles so we can render them all at once */
+ tess->lonelyTriList = NULL;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ f->marked = FALSE;
+ }
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+
+ /* We examine all faces in an arbitrary order. Whenever we find
+ * an unprocessed face F, we output a group of faces including F
+ * whose size is maximum.
+ */
+ if( f->inside && ! f->marked ) {
+ RenderMaximumFaceGroup( tess, f );
+ assert( f->marked );
+ }
+ }
+ if( tess->lonelyTriList != NULL ) {
+ RenderLonelyTriangles( tess, tess->lonelyTriList );
+ tess->lonelyTriList = NULL;
+ }
+}
+
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
+{
+ /* We want to find the largest triangle fan or strip of unmarked faces
+ * which includes the given face fOrig. There are 3 possible fans
+ * passing through fOrig (one centered at each vertex), and 3 possible
+ * strips (one for each CCW permutation of the vertices). Our strategy
+ * is to try all of these, and take the primitive which uses the most
+ * triangles (a greedy approach).
+ */
+ GLUhalfEdge *e = fOrig->anEdge;
+ struct FaceCount max, newFace;
+
+ max.size = 1;
+ max.eStart = e;
+ max.render = &RenderTriangle;
+
+ if( ! tess->flagBoundary ) {
+ newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+
+ newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+ }
+ (*(max.render))( tess, max.eStart, max.size );
+}
+
+
+/* Macros which keep track of faces we have marked temporarily, and allow
+ * us to backtrack when necessary. With triangle fans, this is not
+ * really necessary, since the only awkward case is a loop of triangles
+ * around a single origin vertex. However with strips the situation is
+ * more complicated, and we need a general tracking method like the
+ * one here.
+ */
+#define Marked(f) (! (f)->inside || (f)->marked)
+
+#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
+
+#define FreeTrail(t) do { \
+ while( (t) != NULL ) { \
+ (t)->marked = FALSE; t = (t)->trail; \
+ } \
+ } while(0) /* absorb trailing semicolon */
+
+
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
+{
+ /* eOrig->Lface is the face we want to render. We want to find the size
+ * of a maximal fan around eOrig->Org. To do this we just walk around
+ * the origin vertex as far as possible in both directions.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderFan };
+ GLUface *trail = NULL;
+ GLUhalfEdge *e;
+
+ for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++newFace.size;
+ }
+ for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
+ AddToTrail( e->Rface, trail );
+ ++newFace.size;
+ }
+ newFace.eStart = e;
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+#define IsEven(n) (((n) & 1) == 0)
+
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
+{
+ /* Here we are looking for a maximal strip that contains the vertices
+ * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
+ * reverse, such that all triangles are oriented CCW).
+ *
+ * Again we walk forward and backward as far as possible. However for
+ * strips there is a twist: to get CCW orientations, there must be
+ * an *even* number of triangles in the strip on one side of eOrig.
+ * We walk the strip starting on a side with an even number of triangles;
+ * if both side have an odd number, we are forced to shorten one side.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderStrip };
+ long headSize = 0, tailSize = 0;
+ GLUface *trail = NULL;
+ GLUhalfEdge *e, *eTail, *eHead;
+
+ for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++tailSize;
+ e = e->Dprev;
+ if( Marked( e->Lface )) break;
+ AddToTrail( e->Lface, trail );
+ }
+ eTail = e;
+
+ for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
+ AddToTrail( e->Rface, trail );
+ ++headSize;
+ e = e->Oprev;
+ if( Marked( e->Rface )) break;
+ AddToTrail( e->Rface, trail );
+ }
+ eHead = e;
+
+ newFace.size = tailSize + headSize;
+ if( IsEven( tailSize )) {
+ newFace.eStart = eTail->Sym;
+ } else if( IsEven( headSize )) {
+ newFace.eStart = eHead;
+ } else {
+ /* Both sides have odd length, we must shorten one of them. In fact,
+ * we must start from eHead to guarantee inclusion of eOrig->Lface.
+ */
+ --newFace.size;
+ newFace.eStart = eHead->Onext;
+ }
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Just add the triangle to a triangle list, so we can render all
+ * the separate triangles at once.
+ */
+ assert( size == 1 );
+ AddToTrail( e->Lface, tess->lonelyTriList );
+}
+
+
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
+{
+ /* Now we render all the separate triangles which could not be
+ * grouped into a triangle fan or strip.
+ */
+ GLUhalfEdge *e;
+ int newState;
+ int edgeState = -1; /* force edge state output for first vertex */
+
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
+
+ for( ; f != NULL; f = f->trail ) {
+ /* Loop once for each edge (there will always be 3 edges) */
+
+ e = f->anEdge;
+ do {
+ if( tess->flagBoundary ) {
+ /* Set the "edge state" to TRUE just before we output the
+ * first vertex of each edge on the polygon boundary.
+ */
+ newState = ! e->Rface->inside;
+ if( edgeState != newState ) {
+ edgeState = newState;
+ CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
+ }
+ }
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a fan starting from
+ * edge "e". The fan *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a strip starting from
+ * edge "e". The strip *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Dprev;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ if( Marked( e->Lface )) break;
+
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+/************************ Boundary contour decomposition ******************/
+
+/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
+ * contour for each face marked "inside". The rendering output is
+ * provided as callbacks (see the api).
+ */
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+ GLUhalfEdge *e;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ if( f->inside ) {
+ CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
+ e = f->anEdge;
+ do {
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ CALL_END_OR_END_DATA();
+ }
+ }
+}
+
+
+/************************ Quick-and-dirty decomposition ******************/
+
+#define SIGN_INCONSISTENT 2
+
+static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
+/*
+ * If check==FALSE, we compute the polygon normal and place it in norm[].
+ * If check==TRUE, we check that each triangle in the fan from v0 has a
+ * consistent orientation with respect to norm[]. If triangles are
+ * consistently oriented CCW, return 1; if CW, return -1; if all triangles
+ * are degenerate return 0; otherwise (no consistent orientation) return
+ * SIGN_INCONSISTENT.
+ */
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
+ int sign = 0;
+
+ /* Find the polygon normal. It is important to get a reasonable
+ * normal even when the polygon is self-intersecting (eg. a bowtie).
+ * Otherwise, the computed normal could be very tiny, but perpendicular
+ * to the true plane of the polygon due to numerical noise. Then all
+ * the triangles would appear to be degenerate and we would incorrectly
+ * decompose the polygon as a fan (or simply not render it at all).
+ *
+ * We use a sum-of-triangles normal algorithm rather than the more
+ * efficient sum-of-trapezoids method (used in CheckOrientation()
+ * in normal.c). This lets us explicitly reverse the signed area
+ * of some triangles to get a reasonable normal in the self-intersecting
+ * case.
+ */
+ if( ! check ) {
+ norm[0] = norm[1] = norm[2] = 0.0;
+ }
+
+ vc = v0 + 1;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+ while( ++vc < vn ) {
+ xp = xc; yp = yc; zp = zc;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+
+ /* Compute (vp - v0) cross (vc - v0) */
+ n[0] = yp*zc - zp*yc;
+ n[1] = zp*xc - xp*zc;
+ n[2] = xp*yc - yp*xc;
+
+ dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
+ if( ! check ) {
+ /* Reverse the contribution of back-facing triangles to get
+ * a reasonable normal for self-intersecting polygons (see above)
+ */
+ if( dot >= 0 ) {
+ norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
+ } else {
+ norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
+ }
+ } else if( dot != 0 ) {
+ /* Check the new orientation for consistency with previous triangles */
+ if( dot > 0 ) {
+ if( sign < 0 ) return SIGN_INCONSISTENT;
+ sign = 1;
+ } else {
+ if( sign > 0 ) return SIGN_INCONSISTENT;
+ sign = -1;
+ }
+ }
+ }
+ return sign;
+}
+
+/* __gl_renderCache( tess ) takes a single contour and tries to render it
+ * as a triangle fan. This handles convex polygons, as well as some
+ * non-convex polygons if we get lucky.
+ *
+ * Returns TRUE if the polygon was successfully rendered. The rendering
+ * output is provided as callbacks (see the api).
+ */
+GLboolean __gl_renderCache( GLUtesselator *tess )
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble norm[3];
+ int sign;
+
+ if( tess->cacheCount < 3 ) {
+ /* Degenerate contour -- no output */
+ return TRUE;
+ }
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm, FALSE );
+ }
+
+ sign = ComputeNormal( tess, norm, TRUE );
+ if( sign == SIGN_INCONSISTENT ) {
+ /* Fan triangles did not have a consistent orientation */
+ return FALSE;
+ }
+ if( sign == 0 ) {
+ /* All triangles were degenerate */
+ return TRUE;
+ }
+
+ /* Make sure we do the right thing for each winding rule */
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ break;
+ case GLU_TESS_WINDING_POSITIVE:
+ if( sign < 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_NEGATIVE:
+ if( sign > 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return TRUE;
+ }
+
+ CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
+ : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
+ : GL_TRIANGLES );
+
+ CALL_VERTEX_OR_VERTEX_DATA( v0->data );
+ if( sign > 0 ) {
+ for( vc = v0+1; vc < vn; ++vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ } else {
+ for( vc = vn-1; vc > v0; --vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ }
+ CALL_END_OR_END_DATA();
+ return TRUE;
+}
diff --git a/vtm/jni/tessellate/render.h b/vtm/jni/tessellate/render.h
new file mode 100644
index 00000000..a298c9a9
--- /dev/null
+++ b/vtm/jni/tessellate/render.h
@@ -0,0 +1,52 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __render_h_
+#define __render_h_
+
+#include "mesh.h"
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
+
+GLboolean __gl_renderCache( GLUtesselator *tess );
+
+#endif
diff --git a/vtm/jni/tessellate/sweep.c b/vtm/jni/tessellate/sweep.c
new file mode 100644
index 00000000..eca828ff
--- /dev/null
+++ b/vtm/jni/tessellate/sweep.c
@@ -0,0 +1,1361 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include
+#include
+#include /* longjmp */
+#include /* LONG_MAX */
+
+#include "mesh.h"
+#include "geom.h"
+#include "tess.h"
+#include "dict.h"
+#include "priorityq.h"
+#include "memalloc.h"
+#include "sweep.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+extern void DebugEvent( GLUtesselator *tess );
+#else
+#define DebugEvent( tess )
+#endif
+
+/*
+ * Invariants for the Edge Dictionary.
+ * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ * at any valid location of the sweep event
+ * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ * share a common endpoint
+ * - for each e, e->Dst has been processed, but not e->Org
+ * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+ * where "event" is the current sweep line event.
+ * - no edge e has zero length
+ *
+ * Invariants for the Mesh (the processed portion).
+ * - the portion of the mesh left of the sweep line is a planar graph,
+ * ie. there is *some* way to embed it in the plane
+ * - no processed edge has zero length
+ * - no two processed vertices have identical coordinates
+ * - each "inside" region is monotone, ie. can be broken into two chains
+ * of monotonically increasing vertices according to VertLeq(v1,v2)
+ * - a non-invariant: these chains may intersect (very slightly)
+ *
+ * Invariants for the Sweep.
+ * - if none of the edges incident to the event vertex have an activeRegion
+ * (ie. none of these edges are in the edge dictionary), then the vertex
+ * has only right-going edges.
+ * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ * by ConnectRightVertex), then it is the only right-going edge from
+ * its associated vertex. (This says that these edges exist only
+ * when it is necessary.)
+ */
+
+#undef MAX
+#undef MIN
+#define MAX(x,y) ((x) >= (y) ? (x) : (y))
+#define MIN(x,y) ((x) <= (y) ? (x) : (y))
+
+/* When we merge two edges into one, we need to compute the combined
+ * winding of the new edge.
+ */
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );
+
+static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,
+ ActiveRegion *reg2 )
+/*
+ * Both edges must be directed from right to left (this is the canonical
+ * direction for the upper edge of each region).
+ *
+ * The strategy is to evaluate a "t" value for each edge at the
+ * current sweep line position, given by tess->event. The calculations
+ * are designed to be very stable, but of course they are not perfect.
+ *
+ * Special case: if both edge destinations are at the sweep event,
+ * we sort the edges by slope (they would otherwise compare equally).
+ */
+{
+ GLUvertex *event = tess->event;
+ GLUhalfEdge *e1, *e2;
+ GLdouble t1, t2;
+
+ e1 = reg1->eUp;
+ e2 = reg2->eUp;
+
+ if( e1->Dst == event ) {
+ if( e2->Dst == event ) {
+ /* Two edges right of the sweep line which meet at the sweep event.
+ * Sort them by slope.
+ */
+ if( VertLeq( e1->Org, e2->Org )) {
+ return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
+ }
+ return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
+ }
+ return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
+ }
+ if( e2->Dst == event ) {
+ return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
+ }
+
+ /* General case - compute signed distance *from* e1, e2 to event */
+ t1 = EdgeEval( e1->Dst, event, e1->Org );
+ t2 = EdgeEval( e2->Dst, event, e2->Org );
+ return (t1 >= t2);
+}
+
+
+static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg )
+{
+ if( reg->fixUpperEdge ) {
+ /* It was created with zero winding number, so it better be
+ * deleted with zero winding number (ie. it better not get merged
+ * with a real edge).
+ */
+ assert( reg->eUp->winding == 0 );
+ }
+ reg->eUp->activeRegion = NULL;
+ dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */
+ memFree( reg );
+}
+
+
+static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )
+/*
+ * Replace an upper edge which needs fixing (see ConnectRightVertex).
+ */
+{
+ assert( reg->fixUpperEdge );
+ if ( !__gl_meshDelete( reg->eUp ) ) return 0;
+ reg->fixUpperEdge = FALSE;
+ reg->eUp = newEdge;
+ newEdge->activeRegion = reg;
+
+ return 1;
+}
+
+static ActiveRegion *TopLeftRegion( ActiveRegion *reg )
+{
+ GLUvertex *org = reg->eUp->Org;
+ GLUhalfEdge *e;
+
+ /* Find the region above the uppermost edge with the same origin */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Org == org );
+
+ /* If the edge above was a temporary edge introduced by ConnectRightVertex,
+ * now is the time to fix it.
+ */
+ if( reg->fixUpperEdge ) {
+ e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
+ if (e == NULL) return NULL;
+ if ( !FixUpperEdge( reg, e ) ) return NULL;
+ reg = RegionAbove( reg );
+ }
+ return reg;
+}
+
+static ActiveRegion *TopRightRegion( ActiveRegion *reg )
+{
+ GLUvertex *dst = reg->eUp->Dst;
+
+ /* Find the region above the uppermost edge with the same destination */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Dst == dst );
+ return reg;
+}
+
+static ActiveRegion *AddRegionBelow( GLUtesselator *tess,
+ ActiveRegion *regAbove,
+ GLUhalfEdge *eNewUp )
+/*
+ * Add a new active region to the sweep line, *somewhere* below "regAbove"
+ * (according to where the new edge belongs in the sweep-line dictionary).
+ * The upper edge of the new region will be "eNewUp".
+ * Winding number and "inside" flag are not updated.
+ */
+{
+ ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (regNew == NULL) longjmp(tess->env,1);
+
+ regNew->eUp = eNewUp;
+ /* __gl_dictListInsertBefore */
+ regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
+ if (regNew->nodeUp == NULL) longjmp(tess->env,1);
+ regNew->fixUpperEdge = FALSE;
+ regNew->sentinel = FALSE;
+ regNew->dirty = FALSE;
+
+ eNewUp->activeRegion = regNew;
+ return regNew;
+}
+
+static GLboolean IsWindingInside( GLUtesselator *tess, int n )
+{
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ return (n & 1);
+ case GLU_TESS_WINDING_NONZERO:
+ return (n != 0);
+ case GLU_TESS_WINDING_POSITIVE:
+ return (n > 0);
+ case GLU_TESS_WINDING_NEGATIVE:
+ return (n < 0);
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return (n >= 2) || (n <= -2);
+ }
+ /*LINTED*/
+ assert( FALSE );
+ /*NOTREACHED*/
+ return GL_FALSE; /* avoid compiler complaints */
+}
+
+
+static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg )
+{
+ reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+}
+
+
+static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )
+/*
+ * Delete a region from the sweep line. This happens when the upper
+ * and lower chains of a region meet (at a vertex on the sweep line).
+ * The "inside" flag is copied to the appropriate mesh face (we could
+ * not do this before -- since the structure of the mesh is always
+ * changing, this face may not have even existed until now).
+ */
+{
+ GLUhalfEdge *e = reg->eUp;
+ GLUface *f = e->Lface;
+
+ f->inside = reg->inside;
+ f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */
+ DeleteRegion( tess, reg );
+}
+
+
+static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,
+ ActiveRegion *regFirst, ActiveRegion *regLast )
+/*
+ * We are given a vertex with one or more left-going edges. All affected
+ * edges should be in the edge dictionary. Starting at regFirst->eUp,
+ * we walk down deleting all regions where both edges have the same
+ * origin vOrg. At the same time we copy the "inside" flag from the
+ * active region to the face, since at this point each face will belong
+ * to at most one region (this was not necessarily true until this point
+ * in the sweep). The walk stops at the region above regLast; if regLast
+ * is NULL we walk as far as possible. At the same time we relink the
+ * mesh if necessary, so that the ordering of edges around vOrg is the
+ * same as in the dictionary.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ regPrev = regFirst;
+ ePrev = regFirst->eUp;
+ while( regPrev != regLast ) {
+ regPrev->fixUpperEdge = FALSE; /* placement was OK */
+ reg = RegionBelow( regPrev );
+ e = reg->eUp;
+ if( e->Org != ePrev->Org ) {
+ if( ! reg->fixUpperEdge ) {
+ /* Remove the last left-going edge. Even though there are no further
+ * edges in the dictionary with this origin, there may be further
+ * such edges in the mesh (if we are adding left edges to a vertex
+ * that has already been processed). Thus it is important to call
+ * FinishRegion rather than just DeleteRegion.
+ */
+ FinishRegion( tess, regPrev );
+ break;
+ }
+ /* If the edge below was a temporary edge introduced by
+ * ConnectRightVertex, now is the time to fix it.
+ */
+ e = __gl_meshConnect( ePrev->Lprev, e->Sym );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
+ }
+
+ /* Relink edges so that ePrev->Onext == e */
+ if( ePrev->Onext != e ) {
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
+ }
+ FinishRegion( tess, regPrev ); /* may change reg->eUp */
+ ePrev = reg->eUp;
+ regPrev = reg;
+ }
+ return ePrev;
+}
+
+
+static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,
+ GLboolean cleanUp )
+/*
+ * Purpose: insert right-going edges into the edge dictionary, and update
+ * winding numbers and mesh connectivity appropriately. All right-going
+ * edges share a common origin vOrg. Edges are inserted CCW starting at
+ * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any
+ * left-going edges already processed, then eTopLeft must be the edge
+ * such that an imaginary upward vertical segment from vOrg would be
+ * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft
+ * should be NULL.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+ int firstTime = TRUE;
+
+ /* Insert the new right-going edges in the dictionary */
+ e = eFirst;
+ do {
+ assert( VertLeq( e->Org, e->Dst ));
+ AddRegionBelow( tess, regUp, e->Sym );
+ e = e->Onext;
+ } while ( e != eLast );
+
+ /* Walk *all* right-going edges from e->Org, in the dictionary order,
+ * updating the winding numbers of each region, and re-linking the mesh
+ * edges to match the dictionary ordering (if necessary).
+ */
+ if( eTopLeft == NULL ) {
+ eTopLeft = RegionBelow( regUp )->eUp->Rprev;
+ }
+ regPrev = regUp;
+ ePrev = eTopLeft;
+ for( ;; ) {
+ reg = RegionBelow( regPrev );
+ e = reg->eUp->Sym;
+ if( e->Org != ePrev->Org ) break;
+
+ if( e->Onext != ePrev ) {
+ /* Unlink e from its current position, and relink below ePrev */
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
+ }
+ /* Compute the winding number and "inside" flag for the new regions */
+ reg->windingNumber = regPrev->windingNumber - e->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+
+ /* Check for two outgoing edges with same slope -- process these
+ * before any intersection tests (see example in __gl_computeInterior).
+ */
+ regPrev->dirty = TRUE;
+ if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
+ AddWinding( e, ePrev );
+ DeleteRegion( tess, regPrev );
+ if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
+ }
+ firstTime = FALSE;
+ regPrev = reg;
+ ePrev = e;
+ }
+ regPrev->dirty = TRUE;
+ assert( regPrev->windingNumber - e->winding == reg->windingNumber );
+
+ if( cleanUp ) {
+ /* Check for intersections between newly adjacent edges. */
+ WalkDirtyRegions( tess, regPrev );
+ }
+}
+
+
+static void CallCombine( GLUtesselator *tess, GLUvertex *isect,
+ void *data[4], GLfloat weights[4], int needed )
+{
+ GLdouble coords[3];
+
+ /* Copy coord data in case the callback changes it. */
+ coords[0] = isect->coords[0];
+ coords[1] = isect->coords[1];
+ coords[2] = isect->coords[2];
+
+ isect->data = NULL;
+ CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
+ if( isect->data == NULL ) {
+ if( ! needed ) {
+ isect->data = data[0];
+ } else if( ! tess->fatalError ) {
+ /* The only way fatal error is when two edges are found to intersect,
+ * but the user has not provided the callback necessary to handle
+ * generated intersection points.
+ */
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
+ tess->fatalError = TRUE;
+ }
+ }
+}
+
+static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,
+ GLUhalfEdge *e2 )
+/*
+ * Two vertices with idential coordinates are combined into one.
+ * e1->Org is kept, while e2->Org is discarded.
+ */
+{
+ void *data[4] = { NULL, NULL, NULL, NULL };
+ GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
+
+ data[0] = e1->Org->data;
+ data[1] = e2->Org->data;
+ CallCombine( tess, e1->Org, data, weights, FALSE );
+ if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
+}
+
+static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,
+ GLfloat *weights )
+/*
+ * Find some weights which describe how the intersection vertex is
+ * a linear combination of "org" and "dest". Each of the two edges
+ * which generated "isect" is allocated 50% of the weight; each edge
+ * splits the weight between its org and dst according to the
+ * relative distance to "isect".
+ */
+{
+ GLdouble t1 = VertL1dist( org, isect );
+ GLdouble t2 = VertL1dist( dst, isect );
+
+ weights[0] = 0.5 * t2 / (t1 + t2);
+ weights[1] = 0.5 * t1 / (t1 + t2);
+ isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
+ isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
+ isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
+}
+
+
+static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,
+ GLUvertex *orgUp, GLUvertex *dstUp,
+ GLUvertex *orgLo, GLUvertex *dstLo )
+/*
+ * We've computed a new intersection point, now we need a "data" pointer
+ * from the user so that we can refer to this new vertex in the
+ * rendering callbacks.
+ */
+{
+ void *data[4];
+ GLfloat weights[4];
+
+ data[0] = orgUp->data;
+ data[1] = dstUp->data;
+ data[2] = orgLo->data;
+ data[3] = dstLo->data;
+
+ isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
+ VertexWeights( isect, orgUp, dstUp, &weights[0] );
+ VertexWeights( isect, orgLo, dstLo, &weights[2] );
+
+ CallCombine( tess, isect, data, weights, TRUE );
+}
+
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which
+ * origin is leftmost).
+ *
+ * The main purpose is to splice right-going edges with the same
+ * dest vertex and nearly identical slopes (ie. we can't distinguish
+ * the slopes numerically). However the splicing can also help us
+ * to recover from numerical errors. For example, suppose at one
+ * point we checked eUp and eLo, and decided that eUp->Org is barely
+ * above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * our test so that now eUp->Org is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants.
+ *
+ * One possibility is to check these edges for intersection again
+ * (ie. CheckForIntersect). This is what we do if possible. However
+ * CheckForIntersect requires that tess->event lies between eUp and eLo,
+ * so that it has something to fall back on when the intersection
+ * calculation gives us an unusable answer. So, for those cases where
+ * we can't check for intersection, this routine fixes the problem
+ * by just splicing the offending vertex into the other edge.
+ * This is a guaranteed solution, no matter how degenerate things get.
+ * Basically this is a combinatorial solution to a numerical problem.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+
+ if( VertLeq( eUp->Org, eLo->Org )) {
+ if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Org appears to be below eLo */
+ if( ! VertEq( eUp->Org, eLo->Org )) {
+ /* Splice eUp->Org into eLo */
+ if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
+ regUp->dirty = regLo->dirty = TRUE;
+
+ } else if( eUp->Org != eLo->Org ) {
+ /* merge the two vertices, discarding eUp->Org */
+ pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */
+ SpliceMergeVertices( tess, eLo->Oprev, eUp );
+ }
+ } else {
+ if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ }
+ return TRUE;
+}
+
+static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which
+ * destination is rightmost).
+ *
+ * Theoretically, this should always be true. However, splitting an edge
+ * into two pieces can change the results of previous tests. For example,
+ * suppose at one point we checked eUp and eLo, and decided that eUp->Dst
+ * is barely above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * the test so that now eUp->Dst is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants
+ * (otherwise new edges might get inserted in the wrong place in the
+ * dictionary, and bad stuff will happen).
+ *
+ * We fix the problem by just splicing the offending vertex into the
+ * other edge.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( eUp->Dst, eLo->Dst ));
+
+ if( VertLeq( eUp->Dst, eLo->Dst )) {
+ if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ e = __gl_meshSplitEdge( eUp );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
+ e->Lface->inside = regUp->inside;
+ } else {
+ if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */
+ regUp->dirty = regLo->dirty = TRUE;
+ e = __gl_meshSplitEdge( eLo );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
+ e->Rface->inside = regUp->inside;
+ }
+ return TRUE;
+}
+
+
+static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edges of the given region to see if
+ * they intersect. If so, create the intersection and add it
+ * to the data structures.
+ *
+ * Returns TRUE if adding the new intersection resulted in a recursive
+ * call to AddRightEdges(); in this case all "dirty" regions have been
+ * checked for intersections, and possibly regUp has been deleted.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUvertex *orgUp = eUp->Org;
+ GLUvertex *orgLo = eLo->Org;
+ GLUvertex *dstUp = eUp->Dst;
+ GLUvertex *dstLo = eLo->Dst;
+ GLdouble tMinUp, tMaxLo;
+ GLUvertex isect, *orgMin;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( dstLo, dstUp ));
+ assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
+ assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
+ assert( orgUp != tess->event && orgLo != tess->event );
+ assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
+
+ if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */
+
+ tMinUp = MIN( orgUp->t, dstUp->t );
+ tMaxLo = MAX( orgLo->t, dstLo->t );
+ if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */
+
+ if( VertLeq( orgUp, orgLo )) {
+ if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE;
+ } else {
+ if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE;
+ }
+
+ /* At this point the edges intersect, at least marginally */
+ DebugEvent( tess );
+
+ __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
+ /* The following properties are guaranteed: */
+ assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
+ assert( isect.t <= MAX( orgLo->t, dstLo->t ));
+ assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
+ assert( isect.s <= MAX( orgLo->s, orgUp->s ));
+
+ if( VertLeq( &isect, tess->event )) {
+ /* The intersection point lies slightly to the left of the sweep line,
+ * so move it until it''s slightly to the right of the sweep line.
+ * (If we had perfect numerical precision, this would never happen
+ * in the first place). The easiest and safest thing to do is
+ * replace the intersection by tess->event.
+ */
+ isect.s = tess->event->s;
+ isect.t = tess->event->t;
+ }
+ /* Similarly, if the computed intersection lies to the right of the
+ * rightmost origin (which should rarely happen), it can cause
+ * unbelievable inefficiency on sufficiently degenerate inputs.
+ * (If you have the test program, try running test54.d with the
+ * "X zoom" option turned on).
+ */
+ orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
+ if( VertLeq( orgMin, &isect )) {
+ isect.s = orgMin->s;
+ isect.t = orgMin->t;
+ }
+
+ if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
+ /* Easy case -- intersection at one of the right endpoints */
+ (void) CheckForRightSplice( tess, regUp );
+ return FALSE;
+ }
+
+ if( (! VertEq( dstUp, tess->event )
+ && EdgeSign( dstUp, tess->event, &isect ) >= 0)
+ || (! VertEq( dstLo, tess->event )
+ && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
+ {
+ /* Very unusual -- the new upper or lower edge would pass on the
+ * wrong side of the sweep event, or through it. This can happen
+ * due to very small numerical errors in the intersection calculation.
+ */
+ if( dstLo == tess->event ) {
+ /* Splice dstLo into eUp, and process the new region(s) */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eUp = RegionBelow(regUp)->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
+ return TRUE;
+ }
+ if( dstUp == tess->event ) {
+ /* Splice dstUp into eLo, and process the new region(s) */
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
+ regLo = regUp;
+ regUp = TopRightRegion( regUp );
+ e = RegionBelow(regUp)->eUp->Rprev;
+ regLo->eUp = eLo->Oprev;
+ eLo = FinishLeftRegions( tess, regLo, NULL );
+ AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
+ return TRUE;
+ }
+ /* Special case: called from ConnectRightVertex. If either
+ * edge passes on the wrong side of tess->event, split it
+ * (and wait for ConnectRightVertex to splice it appropriately).
+ */
+ if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ eUp->Org->s = tess->event->s;
+ eUp->Org->t = tess->event->t;
+ }
+ if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
+ regUp->dirty = regLo->dirty = TRUE;
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ eLo->Org->s = tess->event->s;
+ eLo->Org->t = tess->event->t;
+ }
+ /* leave the rest for ConnectRightVertex */
+ return FALSE;
+ }
+
+ /* General case -- split both edges, splice into new vertex.
+ * When we do the splice operation, the order of the arguments is
+ * arbitrary as far as correctness goes. However, when the operation
+ * creates a new face, the work done is proportional to the size of
+ * the new face. We expect the faces in the processed part of
+ * the mesh (ie. eUp->Lface) to be smaller than the faces in the
+ * unprocessed original contours (which will be eLo->Oprev->Lface).
+ */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ eUp->Org->s = isect.s;
+ eUp->Org->t = isect.t;
+ eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */
+ if (eUp->Org->pqHandle == LONG_MAX) {
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ longjmp(tess->env,1);
+ }
+ GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
+ RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
+ return FALSE;
+}
+
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * When the upper or lower edge of any region changes, the region is
+ * marked "dirty". This routine walks through all the dirty regions
+ * and makes sure that the dictionary invariants are satisfied
+ * (see the comments at the beginning of this file). Of course
+ * new dirty regions can be created as we make changes to restore
+ * the invariants.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp, *eLo;
+
+ for( ;; ) {
+ /* Find the lowest dirty region (we walk from the bottom up). */
+ while( regLo->dirty ) {
+ regUp = regLo;
+ regLo = RegionBelow(regLo);
+ }
+ if( ! regUp->dirty ) {
+ regLo = regUp;
+ regUp = RegionAbove( regUp );
+ if( regUp == NULL || ! regUp->dirty ) {
+ /* We've walked all the dirty regions */
+ return;
+ }
+ }
+ regUp->dirty = FALSE;
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ if( eUp->Dst != eLo->Dst ) {
+ /* Check that the edge ordering is obeyed at the Dst vertices. */
+ if( CheckForLeftSplice( tess, regUp )) {
+
+ /* If the upper or lower edge was marked fixUpperEdge, then
+ * we no longer need it (since these edges are needed only for
+ * vertices which otherwise have no right-going edges).
+ */
+ if( regLo->fixUpperEdge ) {
+ DeleteRegion( tess, regLo );
+ if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
+ regLo = RegionBelow( regUp );
+ eLo = regLo->eUp;
+ } else if( regUp->fixUpperEdge ) {
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ eUp = regUp->eUp;
+ }
+ }
+ }
+ if( eUp->Org != eLo->Org ) {
+ if( eUp->Dst != eLo->Dst
+ && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
+ && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
+ {
+ /* When all else fails in CheckForIntersect(), it uses tess->event
+ * as the intersection location. To make this possible, it requires
+ * that tess->event lie between the upper and lower edges, and also
+ * that neither of these is marked fixUpperEdge (since in the worst
+ * case it might splice one of these edges into tess->event, and
+ * violate the invariant that fixable edges are the only right-going
+ * edge from their associated vertex).
+ */
+ if( CheckForIntersect( tess, regUp )) {
+ /* WalkDirtyRegions() was called recursively; we're done */
+ return;
+ }
+ } else {
+ /* Even though we can't use CheckForIntersect(), the Org vertices
+ * may violate the dictionary edge ordering. Check and correct this.
+ */
+ (void) CheckForRightSplice( tess, regUp );
+ }
+ }
+ if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
+ /* A degenerate loop consisting of only two edges -- delete it. */
+ AddWinding( eLo, eUp );
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ }
+ }
+}
+
+
+static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eBottomLeft )
+/*
+ * Purpose: connect a "right" vertex vEvent (one where all edges go left)
+ * to the unprocessed portion of the mesh. Since there are no right-going
+ * edges, two regions (one above vEvent and one below) are being merged
+ * into one. "regUp" is the upper of these two regions.
+ *
+ * There are two reasons for doing this (adding a right-going edge):
+ * - if the two regions being merged are "inside", we must add an edge
+ * to keep them separated (the combined region would not be monotone).
+ * - in any case, we must leave some record of vEvent in the dictionary,
+ * so that we can merge vEvent with features that we have not seen yet.
+ * For example, maybe there is a vertical edge which passes just to
+ * the right of vEvent; we would like to splice vEvent into this edge.
+ *
+ * However, we don't want to connect vEvent to just any vertex. We don''t
+ * want the new edge to cross any other edges; otherwise we will create
+ * intersection vertices even when the input data had no self-intersections.
+ * (This is a bad thing; if the user's input data has no intersections,
+ * we don't want to generate any false intersections ourselves.)
+ *
+ * Our eventual goal is to connect vEvent to the leftmost unprocessed
+ * vertex of the combined region (the union of regUp and regLo).
+ * But because of unseen vertices with all right-going edges, and also
+ * new vertices which may be created by edge intersections, we don''t
+ * know where that leftmost unprocessed vertex is. In the meantime, we
+ * connect vEvent to the closest vertex of either chain, and mark the region
+ * as "fixUpperEdge". This flag says to delete and reconnect this edge
+ * to the next processed vertex on the boundary of the combined region.
+ * Quite possibly the vertex we connected to will turn out to be the
+ * closest one, in which case we won''t need to make any changes.
+ */
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *eTopLeft = eBottomLeft->Onext;
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ int degenerate = FALSE;
+
+ if( eUp->Dst != eLo->Dst ) {
+ (void) CheckForIntersect( tess, regUp );
+ }
+
+ /* Possible new degeneracies: upper or lower edge of regUp may pass
+ * through vEvent, or may coincide with new intersection vertex
+ */
+ if( VertEq( eUp->Org, tess->event )) {
+ if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eTopLeft = RegionBelow( regUp )->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ degenerate = TRUE;
+ }
+ if( VertEq( eLo->Org, tess->event )) {
+ if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
+ eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
+ degenerate = TRUE;
+ }
+ if( degenerate ) {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ return;
+ }
+
+ /* Non-degenerate situation -- need to add a temporary, fixable edge.
+ * Connect to the closer of eLo->Org, eUp->Org.
+ */
+ if( VertLeq( eLo->Org, eUp->Org )) {
+ eNew = eLo->Oprev;
+ } else {
+ eNew = eUp;
+ }
+ eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
+ if (eNew == NULL) longjmp(tess->env,1);
+
+ /* Prevent cleanup, otherwise eNew might disappear before we've even
+ * had a chance to mark it as a temporary edge.
+ */
+ AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
+ eNew->Sym->activeRegion->fixUpperEdge = TRUE;
+ WalkDirtyRegions( tess, regUp );
+}
+
+/* Because vertices at exactly the same location are merged together
+ * before we process the sweep event, some degenerate cases can't occur.
+ * However if someone eventually makes the modifications required to
+ * merge features which are close together, the cases below marked
+ * TOLERANCE_NONZERO will be useful. They were debugged before the
+ * code to merge identical vertices in the main loop was added.
+ */
+#define TOLERANCE_NONZERO FALSE
+
+static void ConnectLeftDegenerate( GLUtesselator *tess,
+ ActiveRegion *regUp, GLUvertex *vEvent )
+/*
+ * The event vertex lies exacty on an already-processed edge or vertex.
+ * Adding the new vertex involves splicing it into the already-processed
+ * part of the mesh.
+ */
+{
+ GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast;
+ ActiveRegion *reg;
+
+ e = regUp->eUp;
+ if( VertEq( e->Org, vEvent )) {
+ /* e->Org is an unprocessed vertex - just combine them, and wait
+ * for e->Org to be pulled from the queue
+ */
+ assert( TOLERANCE_NONZERO );
+ SpliceMergeVertices( tess, e, vEvent->anEdge );
+ return;
+ }
+
+ if( ! VertEq( e->Dst, vEvent )) {
+ /* General case -- splice vEvent into edge e which passes through it */
+ if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
+ if( regUp->fixUpperEdge ) {
+ /* This edge was fixable -- delete unused portion of original edge */
+ if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
+ regUp->fixUpperEdge = FALSE;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
+ SweepEvent( tess, vEvent ); /* recurse */
+ return;
+ }
+
+ /* vEvent coincides with e->Dst, which has already been processed.
+ * Splice in the additional right-going edges.
+ */
+ assert( TOLERANCE_NONZERO );
+ regUp = TopRightRegion( regUp );
+ reg = RegionBelow( regUp );
+ eTopRight = reg->eUp->Sym;
+ eTopLeft = eLast = eTopRight->Onext;
+ if( reg->fixUpperEdge ) {
+ /* Here e->Dst has only a single fixable edge going right.
+ * We can delete it since now we have some real right-going edges.
+ */
+ assert( eTopLeft != eTopRight ); /* there are some left edges too */
+ DeleteRegion( tess, reg );
+ if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
+ eTopRight = eTopLeft->Oprev;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
+ if( ! EdgeGoesLeft( eTopLeft )) {
+ /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */
+ eTopLeft = NULL;
+ }
+ AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
+}
+
+
+static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Purpose: connect a "left" vertex (one where both edges go right)
+ * to the processed portion of the mesh. Let R be the active region
+ * containing vEvent, and let U and L be the upper and lower edge
+ * chains of R. There are two possibilities:
+ *
+ * - the normal case: split R into two regions, by connecting vEvent to
+ * the rightmost vertex of U or L lying to the left of the sweep line
+ *
+ * - the degenerate case: if vEvent is close enough to U or L, we
+ * merge vEvent into that edge chain. The subcases are:
+ * - merging with the rightmost vertex of U or L
+ * - merging with the active edge of U or L
+ * - merging with an already-processed portion of U or L
+ */
+{
+ ActiveRegion *regUp, *regLo, *reg;
+ GLUhalfEdge *eUp, *eLo, *eNew;
+ ActiveRegion tmp;
+
+ /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
+
+ /* Get a pointer to the active region containing vEvent */
+ tmp.eUp = vEvent->anEdge->Sym;
+ /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
+ regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
+ regLo = RegionBelow( regUp );
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ /* Try merging with U or L first */
+ if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
+ ConnectLeftDegenerate( tess, regUp, vEvent );
+ return;
+ }
+
+ /* Connect vEvent to rightmost processed vertex of either chain.
+ * e->Dst is the vertex that we will connect to vEvent.
+ */
+ reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
+
+ if( regUp->inside || reg->fixUpperEdge) {
+ if( reg == regUp ) {
+ eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
+ if (eNew == NULL) longjmp(tess->env,1);
+ } else {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
+ if (tempHalfEdge == NULL) longjmp(tess->env,1);
+
+ eNew = tempHalfEdge->Sym;
+ }
+ if( reg->fixUpperEdge ) {
+ if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
+ } else {
+ ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
+ }
+ SweepEvent( tess, vEvent );
+ } else {
+ /* The new vertex is in a region which does not belong to the polygon.
+ * We don''t need to connect this vertex to the rest of the mesh.
+ */
+ AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
+ }
+}
+
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Does everything necessary when the sweep line crosses a vertex.
+ * Updates the mesh and the edge dictionary.
+ */
+{
+ ActiveRegion *regUp, *reg;
+ GLUhalfEdge *e, *eTopLeft, *eBottomLeft;
+
+ tess->event = vEvent; /* for access in EdgeLeq() */
+ DebugEvent( tess );
+
+ /* Check if this vertex is the right endpoint of an edge that is
+ * already in the dictionary. In this case we don't need to waste
+ * time searching for the location to insert new edges.
+ */
+ e = vEvent->anEdge;
+ while( e->activeRegion == NULL ) {
+ e = e->Onext;
+ if( e == vEvent->anEdge ) {
+ /* All edges go right -- not incident to any processed edges */
+ ConnectLeftVertex( tess, vEvent );
+ return;
+ }
+ }
+
+ /* Processing consists of two phases: first we "finish" all the
+ * active regions where both the upper and lower edges terminate
+ * at vEvent (ie. vEvent is closing off these regions).
+ * We mark these faces "inside" or "outside" the polygon according
+ * to their winding number, and delete the edges from the dictionary.
+ * This takes care of all the left-going edges from vEvent.
+ */
+ regUp = TopLeftRegion( e->activeRegion );
+ if (regUp == NULL) longjmp(tess->env,1);
+ reg = RegionBelow( regUp );
+ eTopLeft = reg->eUp;
+ eBottomLeft = FinishLeftRegions( tess, reg, NULL );
+
+ /* Next we process all the right-going edges from vEvent. This
+ * involves adding the edges to the dictionary, and creating the
+ * associated "active regions" which record information about the
+ * regions between adjacent dictionary edges.
+ */
+ if( eBottomLeft->Onext == eTopLeft ) {
+ /* No right-going edges -- add a temporary "fixable" edge */
+ ConnectRightVertex( tess, regUp, eBottomLeft );
+ } else {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ }
+}
+
+
+/* Make the sentinel coordinates big enough that they will never be
+ * merged with real input features. (Even with the largest possible
+ * input contour and the maximum tolerance of 1.0, no merging will be
+ * done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
+ */
+#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD)
+
+static void AddSentinel( GLUtesselator *tess, GLdouble t )
+/*
+ * We add two sentinel edges above and below all other edges,
+ * to avoid special cases at the top and bottom.
+ */
+{
+ GLUhalfEdge *e;
+ ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (reg == NULL) longjmp(tess->env,1);
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) longjmp(tess->env,1);
+
+ e->Org->s = SENTINEL_COORD;
+ e->Org->t = t;
+ e->Dst->s = -SENTINEL_COORD;
+ e->Dst->t = t;
+ tess->event = e->Dst; /* initialize it */
+
+ reg->eUp = e;
+ reg->windingNumber = 0;
+ reg->inside = FALSE;
+ reg->fixUpperEdge = FALSE;
+ reg->sentinel = TRUE;
+ reg->dirty = FALSE;
+ reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */
+ if (reg->nodeUp == NULL) longjmp(tess->env,1);
+}
+
+
+static void InitEdgeDict( GLUtesselator *tess )
+/*
+ * We maintain an ordering of edge intersections with the sweep line.
+ * This order is maintained in a dynamic dictionary.
+ */
+{
+ /* __gl_dictListNewDict */
+ tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq );
+ if (tess->dict == NULL) longjmp(tess->env,1);
+
+ AddSentinel( tess, -SENTINEL_COORD );
+ AddSentinel( tess, SENTINEL_COORD );
+}
+
+
+static void DoneEdgeDict( GLUtesselator *tess )
+{
+ ActiveRegion *reg;
+#ifndef NDEBUG
+ int fixedEdges = 0;
+#endif
+
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
+ /*
+ * At the end of all processing, the dictionary should contain
+ * only the two sentinel edges, plus at most one "fixable" edge
+ * created by ConnectRightVertex().
+ */
+ if( ! reg->sentinel ) {
+ assert( reg->fixUpperEdge );
+ assert( ++fixedEdges == 1 );
+ }
+ assert( reg->windingNumber == 0 );
+ DeleteRegion( tess, reg );
+/* __gl_meshDelete( reg->eUp );*/
+ }
+ dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */
+}
+
+
+static void RemoveDegenerateEdges( GLUtesselator *tess )
+/*
+ * Remove zero-length edges, and contours with fewer than 3 vertices.
+ */
+{
+ GLUhalfEdge *e, *eNext, *eLnext;
+ GLUhalfEdge *eHead = &tess->mesh->eHead;
+
+ /*LINTED*/
+ for( e = eHead->next; e != eHead; e = eNext ) {
+ eNext = e->next;
+ eLnext = e->Lnext;
+
+ if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
+ /* Zero-length edge, contour has at least 3 edges */
+
+ SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */
+ e = eLnext;
+ eLnext = e->Lnext;
+ }
+ if( eLnext->Lnext == e ) {
+ /* Degenerate contour (one or two edges) */
+
+ if( eLnext != e ) {
+ if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
+ }
+ if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
+ }
+ }
+}
+
+static int InitPriorityQ( GLUtesselator *tess )
+/*
+ * Insert all vertices into the priority queue which determines the
+ * order in which vertices cross the sweep line.
+ */
+{
+ PriorityQ *pq;
+ GLUvertex *v, *vHead;
+
+ /* __gl_pqSortNewPriorityQ */
+ pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq );
+ if (pq == NULL) return 0;
+
+ vHead = &tess->mesh->vHead;
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */
+ if (v->pqHandle == LONG_MAX) break;
+ }
+ if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void DonePriorityQ( GLUtesselator *tess )
+{
+ pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */
+}
+
+
+static int RemoveDegenerateFaces( GLUmesh *mesh )
+/*
+ * Delete any degenerate faces with only two edges. WalkDirtyRegions()
+ * will catch almost all of these, but it won't catch degenerate faces
+ * produced by splice operations on already-processed edges.
+ * The two places this can happen are in FinishLeftRegions(), when
+ * we splice in a "temporary" edge produced by ConnectRightVertex(),
+ * and in CheckForLeftSplice(), where we splice already-processed
+ * edges to ensure that our dictionary invariants are not violated
+ * by numerical errors.
+ *
+ * In both these cases it is *very* dangerous to delete the offending
+ * edge at the time, since one of the routines further up the stack
+ * will sometimes be keeping a pointer to that edge.
+ */
+{
+ GLUface *f, *fNext;
+ GLUhalfEdge *e;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ e = f->anEdge;
+ assert( e->Lnext != e );
+
+ if( e->Lnext->Lnext == e ) {
+ /* A face with only two edges */
+ AddWinding( e->Onext, e );
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ return 1;
+}
+
+int __gl_computeInterior( GLUtesselator *tess )
+/*
+ * __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+{
+ GLUvertex *v, *vNext;
+
+ tess->fatalError = FALSE;
+
+ /* Each vertex defines an event for our sweep line. Start by inserting
+ * all the vertices in a priority queue. Events are processed in
+ * lexicographic order, ie.
+ *
+ * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y)
+ */
+ RemoveDegenerateEdges( tess );
+ if ( !InitPriorityQ( tess ) ) return 0; /* if error */
+ InitEdgeDict( tess );
+
+ /* __gl_pqSortExtractMin */
+ while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
+ for( ;; ) {
+ vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */
+ if( vNext == NULL || ! VertEq( vNext, v )) break;
+
+ /* Merge together all vertices at exactly the same location.
+ * This is more efficient than processing them one at a time,
+ * simplifies the code (see ConnectLeftDegenerate), and is also
+ * important for correct handling of certain degenerate cases.
+ * For example, suppose there are two identical edges A and B
+ * that belong to different contours (so without this code they would
+ * be processed by separate sweep events). Suppose another edge C
+ * crosses A and B from above. When A is processed, we split it
+ * at its intersection point with C. However this also splits C,
+ * so when we insert B we may compute a slightly different
+ * intersection point. This might leave two edges with a small
+ * gap between them. This kind of error is especially obvious
+ * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
+ */
+ vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/
+ SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
+ }
+ SweepEvent( tess, v );
+ }
+
+ /* Set tess->event for debugging purposes */
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
+ DebugEvent( tess );
+ DoneEdgeDict( tess );
+ DonePriorityQ( tess );
+
+ if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0;
+ __gl_meshCheckMesh( tess->mesh );
+
+ return 1;
+}
diff --git a/vtm/jni/tessellate/sweep.h b/vtm/jni/tessellate/sweep.h
new file mode 100644
index 00000000..feb68b0f
--- /dev/null
+++ b/vtm/jni/tessellate/sweep.h
@@ -0,0 +1,77 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __sweep_h_
+#define __sweep_h_
+
+#include "mesh.h"
+
+/* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+int __gl_computeInterior( GLUtesselator *tess );
+
+
+/* The following is here *only* for access by debugging routines */
+
+#include "dict.h"
+
+/* For each pair of adjacent edges crossing the sweep line, there is
+ * an ActiveRegion to represent the region between them. The active
+ * regions are kept in sorted order in a dynamic dictionary. As the
+ * sweep line crosses each vertex, we update the affected regions.
+ */
+
+struct ActiveRegion {
+ GLUhalfEdge *eUp; /* upper edge, directed right to left */
+ DictNode *nodeUp; /* dictionary node corresponding to eUp */
+ int windingNumber; /* used to determine which regions are
+ * inside the polygon */
+ GLboolean inside; /* is this region inside the polygon? */
+ GLboolean sentinel; /* marks fake edges at t = +/-infinity */
+ GLboolean dirty; /* marks regions where the upper or lower
+ * edge has changed, but we haven't checked
+ * whether they intersect yet */
+ GLboolean fixUpperEdge; /* marks temporary edges introduced when
+ * we process a "right vertex" (one without
+ * any edges leaving to the right) */
+};
+
+#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp)))
+#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp)))
+
+#endif
diff --git a/vtm/jni/tessellate/tess.c b/vtm/jni/tessellate/tess.c
new file mode 100644
index 00000000..4a0e8dea
--- /dev/null
+++ b/vtm/jni/tessellate/tess.c
@@ -0,0 +1,632 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include
+#include
+#include
+#include "memalloc.h"
+#include "tess.h"
+#include "mesh.h"
+#include "normal.h"
+#include "sweep.h"
+#include "tessmono.h"
+#include "render.h"
+
+#define GLU_TESS_DEFAULT_TOLERANCE 0.0
+#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **dataOut ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
+
+
+/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
+ void *data[4],
+ GLfloat weight[4],
+ void **outData,
+ void *polygonData ) {}
+
+/* Half-edges are allocated in pairs (see mesh.c) */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+#undef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
+ MAX(sizeof(GLUvertex),sizeof(GLUface))))
+
+
+GLUtesselator * GLAPIENTRY
+gluNewTess( void )
+{
+ GLUtesselator *tess;
+
+ /* Only initialize fields which can be changed by the api. Other fields
+ * are initialized where they are used.
+ */
+
+ if (memInit( MAX_FAST_ALLOC ) == 0) {
+ return 0; /* out of memory */
+ }
+ tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
+ if (tess == NULL) {
+ return 0; /* out of memory */
+ }
+
+ tess->state = T_DORMANT;
+
+ tess->normal[0] = 0;
+ tess->normal[1] = 0;
+ tess->normal[2] = 0;
+
+ tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
+ tess->windingRule = GLU_TESS_WINDING_ODD;
+ tess->flagBoundary = FALSE;
+ tess->boundaryOnly = FALSE;
+
+ tess->callBegin = &noBegin;
+ tess->callEdgeFlag = &noEdgeFlag;
+ tess->callVertex = &noVertex;
+ tess->callEnd = &noEnd;
+
+ tess->callError = &noError;
+ tess->callCombine = &noCombine;
+ tess->callMesh = &noMesh;
+
+ tess->callBeginData= &__gl_noBeginData;
+ tess->callEdgeFlagData= &__gl_noEdgeFlagData;
+ tess->callVertexData= &__gl_noVertexData;
+ tess->callEndData= &__gl_noEndData;
+ tess->callErrorData= &__gl_noErrorData;
+ tess->callCombineData= &__gl_noCombineData;
+
+ tess->polygonData= NULL;
+
+ return tess;
+}
+
+static void MakeDormant( GLUtesselator *tess )
+{
+ /* Return the tessellator to its original dormant state. */
+
+ if( tess->mesh != NULL ) {
+ __gl_meshDeleteMesh( tess->mesh );
+ }
+ tess->state = T_DORMANT;
+ tess->lastEdge = NULL;
+ tess->mesh = NULL;
+}
+
+#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
+
+static void GotoState( GLUtesselator *tess, enum TessState newState )
+{
+ while( tess->state != newState ) {
+ /* We change the current state one level at a time, to get to
+ * the desired state.
+ */
+ if( tess->state < newState ) {
+ switch( tess->state ) {
+ case T_DORMANT:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
+ gluTessBeginPolygon( tess, NULL );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
+ gluTessBeginContour( tess );
+ break;
+ default:
+ ;
+ }
+ } else {
+ switch( tess->state ) {
+ case T_IN_CONTOUR:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
+ gluTessEndContour( tess );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
+ /* gluTessEndPolygon( tess ) is too much work! */
+ MakeDormant( tess );
+ break;
+ default:
+ ;
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+gluDeleteTess( GLUtesselator *tess )
+{
+ RequireState( tess, T_DORMANT );
+ memFree( tess );
+}
+
+
+void GLAPIENTRY
+gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
+{
+ GLenum windingRule;
+
+ switch( which ) {
+ case GLU_TESS_TOLERANCE:
+ if( value < 0.0 || value > 1.0 ) break;
+ tess->relTolerance = value;
+ return;
+
+ case GLU_TESS_WINDING_RULE:
+ windingRule = (GLenum) value;
+ if( windingRule != value ) break; /* not an integer */
+
+ switch( windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ case GLU_TESS_WINDING_POSITIVE:
+ case GLU_TESS_WINDING_NEGATIVE:
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ tess->windingRule = windingRule;
+ return;
+ default:
+ break;
+ }
+
+ case GLU_TESS_BOUNDARY_ONLY:
+ tess->boundaryOnly = (value != 0);
+ return;
+
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
+}
+
+/* Returns tessellator property */
+void GLAPIENTRY
+gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
+{
+ switch (which) {
+ case GLU_TESS_TOLERANCE:
+ /* tolerance should be in range [0..1] */
+ assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
+ *value= tess->relTolerance;
+ break;
+ case GLU_TESS_WINDING_RULE:
+ assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
+ tess->windingRule == GLU_TESS_WINDING_NONZERO ||
+ tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
+ tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
+ tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
+ *value= tess->windingRule;
+ break;
+ case GLU_TESS_BOUNDARY_ONLY:
+ assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
+ *value= tess->boundaryOnly;
+ break;
+ default:
+ *value= 0.0;
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ break;
+ }
+} /* gluGetTessProperty() */
+
+void GLAPIENTRY
+gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
+{
+ tess->normal[0] = x;
+ tess->normal[1] = y;
+ tess->normal[2] = z;
+}
+
+void GLAPIENTRY
+gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
+{
+ switch( which ) {
+ case GLU_TESS_BEGIN:
+ tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_BEGIN_DATA:
+ tess->callBeginData = (fn == NULL) ?
+ &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_EDGE_FLAG:
+ tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
+ (void (GLAPIENTRY *)(GLboolean)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_EDGE_FLAG_DATA:
+ tess->callEdgeFlagData= (fn == NULL) ?
+ &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_VERTEX:
+ tess->callVertex = (fn == NULL) ? &noVertex :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_VERTEX_DATA:
+ tess->callVertexData = (fn == NULL) ?
+ &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
+ return;
+ case GLU_TESS_END:
+ tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
+ return;
+ case GLU_TESS_END_DATA:
+ tess->callEndData = (fn == NULL) ? &__gl_noEndData :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_ERROR:
+ tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_ERROR_DATA:
+ tess->callErrorData = (fn == NULL) ?
+ &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_COMBINE:
+ tess->callCombine = (fn == NULL) ? &noCombine :
+ (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
+ return;
+ case GLU_TESS_COMBINE_DATA:
+ tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
+ (void (GLAPIENTRY *)(GLdouble [3],
+ void *[4],
+ GLfloat [4],
+ void **,
+ void *)) fn;
+ return;
+ case GLU_TESS_MESH:
+ tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
+ return;
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+}
+
+static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ GLUhalfEdge *e;
+
+ e = tess->lastEdge;
+ if( e == NULL ) {
+ /* Make a self-loop (one vertex, one edge). */
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) return 0;
+ if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
+ } else {
+ /* Create a new vertex and edge which immediately follow e
+ * in the ordering around the left face.
+ */
+ if (__gl_meshSplitEdge( e ) == NULL) return 0;
+ e = e->Lnext;
+ }
+
+ /* The new vertex is now e->Org. */
+ e->Org->data = data;
+ e->Org->coords[0] = coords[0];
+ e->Org->coords[1] = coords[1];
+ e->Org->coords[2] = coords[2];
+
+ /* The winding of an edge says how the winding number changes as we
+ * cross from the edge''s right face to its left face. We add the
+ * vertices in such an order that a CCW contour will add +1 to
+ * the winding number of the region inside the contour.
+ */
+ e->winding = 1;
+ e->Sym->winding = -1;
+
+ tess->lastEdge = e;
+
+ return 1;
+}
+
+
+static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ CachedVertex *v = &tess->cache[tess->cacheCount];
+
+ v->data = data;
+ v->coords[0] = coords[0];
+ v->coords[1] = coords[1];
+ v->coords[2] = coords[2];
+ ++tess->cacheCount;
+}
+
+
+static int EmptyCache( GLUtesselator *tess )
+{
+ CachedVertex *v = tess->cache;
+ CachedVertex *vLast;
+
+ tess->mesh = __gl_meshNewMesh();
+ if (tess->mesh == NULL) return 0;
+
+ for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
+ if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
+ }
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+
+ return 1;
+}
+
+
+void GLAPIENTRY
+gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ int i, tooLarge = FALSE;
+ GLdouble x, clamped[3];
+
+ RequireState( tess, T_IN_CONTOUR );
+
+ if( tess->emptyCache ) {
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ tess->lastEdge = NULL;
+ }
+ for( i = 0; i < 3; ++i ) {
+ x = coords[i];
+ if( x < - GLU_TESS_MAX_COORD ) {
+ x = - GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ if( x > GLU_TESS_MAX_COORD ) {
+ x = GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ clamped[i] = x;
+ }
+ if( tooLarge ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
+ }
+
+ if( tess->mesh == NULL ) {
+ if( tess->cacheCount < TESS_MAX_CACHE ) {
+ CacheVertex( tess, clamped, data );
+ return;
+ }
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ }
+ if ( !AddVertex( tess, clamped, data ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ }
+}
+
+
+void GLAPIENTRY
+gluTessBeginPolygon( GLUtesselator *tess, void *data )
+{
+ RequireState( tess, T_DORMANT );
+
+ tess->state = T_IN_POLYGON;
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+ tess->mesh = NULL;
+
+ tess->polygonData= data;
+}
+
+
+void GLAPIENTRY
+gluTessBeginContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_POLYGON );
+
+ tess->state = T_IN_CONTOUR;
+ tess->lastEdge = NULL;
+ if( tess->cacheCount > 0 ) {
+ /* Just set a flag so we don't get confused by empty contours
+ * -- these can be generated accidentally with the obsolete
+ * NextContour() interface.
+ */
+ tess->emptyCache = TRUE;
+ }
+}
+
+
+void GLAPIENTRY
+gluTessEndContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_CONTOUR );
+ tess->state = T_IN_POLYGON;
+}
+
+void GLAPIENTRY
+gluTessEndPolygon( GLUtesselator *tess )
+{
+ GLUmesh *mesh;
+
+ if (setjmp(tess->env) != 0) {
+ /* come back here if out of memory */
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+
+ RequireState( tess, T_IN_POLYGON );
+ tess->state = T_DORMANT;
+
+ if( tess->mesh == NULL ) {
+ if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
+
+ /* Try some special code to make the easy cases go quickly
+ * (eg. convex polygons). This code does NOT handle multiple contours,
+ * intersections, edge flags, and of course it does not generate
+ * an explicit mesh either.
+ */
+ if( __gl_renderCache( tess )) {
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
+ }
+
+ /* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+ __gl_projectPolygon( tess );
+
+ /* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+ if ( !__gl_computeInterior( tess ) ) {
+ longjmp(tess->env,1); /* could've used a label */
+ }
+
+ mesh = tess->mesh;
+ if( ! tess->fatalError ) {
+ int rc = 1;
+
+ /* If the user wants only the boundary contours, we throw away all edges
+ * except those which separate the interior from the exterior.
+ * Otherwise we tessellate all the regions marked "inside".
+ */
+ if( tess->boundaryOnly ) {
+ rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
+ } else {
+ rc = __gl_meshTessellateInterior( mesh );
+ }
+ if (rc == 0) longjmp(tess->env,1); /* could've used a label */
+
+ __gl_meshCheckMesh( mesh );
+
+ if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
+ || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
+ || tess->callBeginData != &__gl_noBeginData
+ || tess->callEndData != &__gl_noEndData
+ || tess->callVertexData != &__gl_noVertexData
+ || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
+ {
+ if( tess->boundaryOnly ) {
+ __gl_renderBoundary( tess, mesh ); /* output boundary contours */
+ } else {
+ __gl_renderMesh( tess, mesh ); /* output strips and fans */
+ }
+ }
+ if( tess->callMesh != &noMesh ) {
+
+ /* Throw away the exterior faces, so that all faces are interior.
+ * This way the user doesn't have to check the "inside" flag,
+ * and we don't need to even reveal its existence. It also leaves
+ * the freedom for an implementation to not generate the exterior
+ * faces in the first place.
+ */
+ __gl_meshDiscardExterior( mesh );
+ (*tess->callMesh)( mesh ); /* user wants the mesh itself */
+ tess->mesh = NULL;
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ __gl_meshDeleteMesh( mesh );
+ tess->polygonData= NULL;
+ tess->mesh = NULL;
+}
+
+
+/*XXXblythe unused function*/
+#if 0
+void GLAPIENTRY
+gluDeleteMesh( GLUmesh *mesh )
+{
+ __gl_meshDeleteMesh( mesh );
+}
+#endif
+
+
+
+/*******************************************************/
+
+/* Obsolete calls -- for backward compatibility */
+
+void GLAPIENTRY
+gluBeginPolygon( GLUtesselator *tess )
+{
+ gluTessBeginPolygon( tess, NULL );
+ gluTessBeginContour( tess );
+}
+
+
+/*ARGSUSED*/
+void GLAPIENTRY
+gluNextContour( GLUtesselator *tess, GLenum type )
+{
+ gluTessEndContour( tess );
+ gluTessBeginContour( tess );
+}
+
+
+void GLAPIENTRY
+gluEndPolygon( GLUtesselator *tess )
+{
+ gluTessEndContour( tess );
+ gluTessEndPolygon( tess );
+}
diff --git a/vtm/jni/tessellate/tess.h b/vtm/jni/tessellate/tess.h
new file mode 100644
index 00000000..5c885d7a
--- /dev/null
+++ b/vtm/jni/tessellate/tess.h
@@ -0,0 +1,165 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __tess_h_
+#define __tess_h_
+
+#include "glu.h"
+#include
+#include "mesh.h"
+#include "dict.h"
+#include "priorityq.h"
+
+/* The begin/end calls must be properly nested. We keep track of
+ * the current state to enforce the ordering.
+ */
+enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
+
+/* We cache vertex data for single-contour polygons so that we can
+ * try a quick-and-dirty decomposition first.
+ */
+#define TESS_MAX_CACHE 100
+
+typedef struct CachedVertex {
+ GLdouble coords[3];
+ void *data;
+} CachedVertex;
+
+struct GLUtesselator {
+
+ /*** state needed for collecting the input data ***/
+
+ enum TessState state; /* what begin/end calls have we seen? */
+
+ GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
+ GLUmesh *mesh; /* stores the input contours, and eventually
+ the tessellation itself */
+
+ void (GLAPIENTRY *callError)( GLenum errnum );
+
+ /*** state needed for projecting onto the sweep plane ***/
+
+ GLdouble normal[3]; /* user-specified normal (if provided) */
+ GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */
+ GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */
+
+ /*** state needed for the line sweep ***/
+
+ GLdouble relTolerance; /* tolerance for merging features */
+ GLenum windingRule; /* rule for determining polygon interior */
+ GLboolean fatalError; /* fatal error: needed combine callback */
+
+ Dict *dict; /* edge dictionary for sweep line */
+ PriorityQ *pq; /* priority queue of vertex events */
+ GLUvertex *event; /* current sweep event being processed */
+
+ void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData );
+
+ /*** state needed for rendering callbacks (see render.c) ***/
+
+ GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
+ GLboolean boundaryOnly; /* Extract contours, not triangles */
+ GLUface *lonelyTriList;
+ /* list of triangles which could not be rendered as strips or fans */
+
+ void (GLAPIENTRY *callBegin)( GLenum type );
+ void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
+ void (GLAPIENTRY *callVertex)( void *data );
+ void (GLAPIENTRY *callEnd)( void );
+ void (GLAPIENTRY *callMesh)( GLUmesh *mesh );
+
+
+ /*** state needed to cache single-contour polygons for renderCache() */
+
+ GLboolean emptyCache; /* empty cache on next vertex() call */
+ int cacheCount; /* number of cached vertices */
+ CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */
+
+ /*** rendering callbacks that also pass polygon data ***/
+ void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
+ void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,
+ void *polygonData );
+ void (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
+ void (GLAPIENTRY *callEndData)( void *polygonData );
+ void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
+ void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+ jmp_buf env; /* place to jump to when memAllocs fail */
+
+ void *polygonData; /* client data for current polygon */
+};
+
+void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
+void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
+void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
+void GLAPIENTRY __gl_noEndData( void *polygonData );
+void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
+void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+#define CALL_BEGIN_OR_BEGIN_DATA(a) \
+ if (tess->callBeginData != &__gl_noBeginData) \
+ (*tess->callBeginData)((a),tess->polygonData); \
+ else (*tess->callBegin)((a));
+
+#define CALL_VERTEX_OR_VERTEX_DATA(a) \
+ if (tess->callVertexData != &__gl_noVertexData) \
+ (*tess->callVertexData)((a),tess->polygonData); \
+ else (*tess->callVertex)((a));
+
+#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
+ if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
+ (*tess->callEdgeFlagData)((a),tess->polygonData); \
+ else (*tess->callEdgeFlag)((a));
+
+#define CALL_END_OR_END_DATA() \
+ if (tess->callEndData != &__gl_noEndData) \
+ (*tess->callEndData)(tess->polygonData); \
+ else (*tess->callEnd)();
+
+#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
+ if (tess->callCombineData != &__gl_noCombineData) \
+ (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
+ else (*tess->callCombine)((a),(b),(c),(d));
+
+#define CALL_ERROR_OR_ERROR_DATA(a) \
+ if (tess->callErrorData != &__gl_noErrorData) \
+ (*tess->callErrorData)((a),tess->polygonData); \
+ else (*tess->callError)((a));
+
+#endif
diff --git a/vtm/jni/tessellate/tessellate.c b/vtm/jni/tessellate/tessellate.c
new file mode 100644
index 00000000..d0e2d649
--- /dev/null
+++ b/vtm/jni/tessellate/tessellate.c
@@ -0,0 +1,382 @@
+#include
+#include
+#include "glu.h"
+#include "tess.h"
+#include
+#include
+
+#ifdef __ANDROID__
+#include
+#endif
+
+#ifndef uintptr_t
+typedef unsigned long uintptr_t;
+#endif
+/******************************************************************************/
+
+typedef struct Triangle {
+ int v[3];
+ struct Triangle *prev;
+} Triangle;
+
+typedef struct Vertex {
+ double pt[3];
+ int index;
+ struct Vertex *prev;
+} Vertex;
+
+typedef struct TessContext {
+ Triangle *latest_t;
+ int n_tris;
+
+ Vertex *v_prev;
+ Vertex *v_prevprev;
+ Vertex *latest_v;
+ GLenum current_mode;
+ int odd_even_strip;
+
+ void (*vertex_cb)(Vertex *, struct TessContext *);
+} TessContext;
+
+void skip_vertex(Vertex *v, TessContext *ctx);
+
+/******************************************************************************/
+
+TessContext *new_tess_context()
+{
+ TessContext *result = (TessContext *) malloc(sizeof(struct TessContext));
+ result->latest_t = NULL;
+ result->latest_v = NULL;
+ result->n_tris = 0;
+ result->v_prev = NULL;
+ result->v_prevprev = NULL;
+ result->v_prev = NULL;
+ result->v_prev = NULL;
+ result->vertex_cb = &skip_vertex;
+ result->odd_even_strip = 0;
+ return result;
+}
+
+void destroy_tess_context(TessContext *ctx)
+{
+ free(ctx);
+}
+
+Vertex *new_vertex(TessContext *ctx, double x, double y)
+{
+ Vertex *result = (Vertex *) malloc(sizeof(Vertex));
+ result->prev = ctx->latest_v;
+ result->pt[0] = x;
+ result->pt[1] = y;
+ result->pt[2] = 0;
+
+ if (ctx->latest_v == NULL) {
+ result->index = 0;
+ }
+ else {
+ result->index = ctx->latest_v->index + 1;
+ }
+ return ctx->latest_v = result;
+}
+
+Triangle *new_triangle(TessContext *ctx, int v1, int v2, int v3)
+{
+ Triangle *result = (Triangle *) malloc(sizeof(Triangle));
+ result->prev = ctx->latest_t;
+ result->v[0] = v1;
+ result->v[1] = v2;
+ result->v[2] = v3;
+ ctx->n_tris++;
+ return ctx->latest_t = result;
+}
+
+/******************************************************************************/
+
+void skip_vertex(Vertex *v, TessContext *ctx) {
+}
+;
+
+void fan_vertex(Vertex *v, TessContext *ctx) {
+ if (ctx->v_prevprev == NULL) {
+ ctx->v_prevprev = v;
+ return;
+ }
+ if (ctx->v_prev == NULL) {
+ ctx->v_prev = v;
+ return;
+ }
+ new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
+ ctx->v_prev = v;
+}
+
+void strip_vertex(Vertex *v, TessContext *ctx)
+{
+ if (ctx->v_prev == NULL) {
+ ctx->v_prev = v;
+ return;
+ }
+ if (ctx->v_prevprev == NULL) {
+ ctx->v_prevprev = v;
+ return;
+ }
+ if (ctx->odd_even_strip) {
+ new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
+ }
+ else {
+ new_triangle(ctx, ctx->v_prev->index, ctx->v_prevprev->index, v->index);
+ }
+ ctx->odd_even_strip = !ctx->odd_even_strip;
+
+ ctx->v_prev = ctx->v_prevprev;
+ ctx->v_prevprev = v;
+}
+
+void triangle_vertex(Vertex *v, TessContext *ctx) {
+ if (ctx->v_prevprev == NULL) {
+ ctx->v_prevprev = v;
+ return;
+ }
+ if (ctx->v_prev == NULL) {
+ ctx->v_prev = v;
+ return;
+ }
+ new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
+ ctx->v_prev = ctx->v_prevprev = NULL;
+}
+
+void vertex(void *vertex_data, void *poly_data)
+{
+ Vertex *ptr = (Vertex *) vertex_data;
+ TessContext *ctx = (TessContext *) poly_data;
+ ctx->vertex_cb(ptr, ctx);
+}
+
+void begin(GLenum which, void *poly_data)
+{
+ TessContext *ctx = (TessContext *) poly_data;
+ ctx->v_prev = ctx->v_prevprev = NULL;
+ ctx->odd_even_strip = 0;
+ switch (which) {
+ case GL_TRIANGLES:
+ ctx->vertex_cb = &triangle_vertex;
+ break;
+ case GL_TRIANGLE_STRIP:
+ ctx->vertex_cb = &strip_vertex;
+ break;
+ case GL_TRIANGLE_FAN:
+ ctx->vertex_cb = &fan_vertex;
+ break;
+ default:
+ printf(stderr, "ERROR, can't handle %d\n", (int) which);
+ ctx->vertex_cb = &skip_vertex;
+ break;
+ }
+}
+
+void combine(const GLdouble newVertex[3],
+ const void *neighborVertex[4],
+ const GLfloat neighborWeight[4], void **outData, void *polyData)
+{
+ TessContext *ctx = (TessContext *) polyData;
+ Vertex *result = new_vertex(ctx, newVertex[0], newVertex[1]);
+ *outData = result;
+}
+
+void write_output(TessContext *ctx, float **coordinates_out, int **tris_out, int *vc, int *tc)
+{
+ int n_verts = 1 + ctx->latest_v->index;
+ *vc = n_verts;
+ int n_tris_copy = ctx->n_tris;
+ *tc = ctx->n_tris;
+ *coordinates_out = malloc(n_verts * sizeof(float) * 2);
+ *tris_out = (ctx->n_tris ? malloc(ctx->n_tris * sizeof(int) * 3) : NULL);
+
+ while (ctx->latest_v) {
+ (*coordinates_out)[2 * ctx->latest_v->index] = ctx->latest_v->pt[0];
+ (*coordinates_out)[2 * ctx->latest_v->index + 1] = ctx->latest_v->pt[1];
+ Vertex *prev = ctx->latest_v->prev;
+ free(ctx->latest_v);
+ ctx->latest_v = prev;
+ }
+
+ while (ctx->latest_t) {
+ (*tris_out)[3 * (n_tris_copy - 1)] = ctx->latest_t->v[0];
+ (*tris_out)[3 * (n_tris_copy - 1) + 1] = ctx->latest_t->v[1];
+ (*tris_out)[3 * (n_tris_copy - 1) + 2] = ctx->latest_t->v[2];
+ Triangle *prev = ctx->latest_t->prev;
+ free(ctx->latest_t);
+ ctx->latest_t = prev;
+ n_tris_copy--;
+ }
+}
+
+TessContext *tessellate(
+ int *nverts,
+ int *ntris,
+ const float **contoursbegin,
+ const float **contoursend)
+{
+ const float *contourbegin, *contourend;
+ Vertex *current_vertex;
+ GLUtesselator *tess;
+ TessContext *ctx;
+
+ tess = gluNewTess();
+ ctx = new_tess_context();
+
+ gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*)()) &vertex);
+ gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid (*)()) &begin);
+ gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (*)()) &combine);
+
+ gluTessBeginPolygon(tess, ctx);
+ do {
+ contourbegin = *contoursbegin++;
+ contourend = *contoursbegin;
+ gluTessBeginContour(tess);
+ while (contourbegin != contourend) {
+ current_vertex = new_vertex(ctx, contourbegin[0], contourbegin[1]);
+ contourbegin += 2;
+ gluTessVertex(tess, current_vertex->pt, current_vertex);
+ }
+ gluTessEndContour(tess);
+ } while (contoursbegin != (contoursend - 1));
+ gluTessEndPolygon(tess);
+
+ //write_output(ctx, verts, tris, nverts, ntris);
+ //destroy_tess_context(ctx);
+
+ gluDeleteTess(tess);
+
+ return ctx;
+}
+#ifdef __ANDROID__
+#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "Tesselate", __VA_ARGS__)
+#endif
+
+#define CAST_CTX(x) (TessContext *)(uintptr_t) x
+
+void Java_org_oscim_renderer_sublayers_MeshLayer_tessFinish(JNIEnv *env, jclass c,
+ jlong ptr_context) {
+
+ TessContext *ctx = CAST_CTX(ptr_context);
+
+ while (ctx->latest_v) {
+ Vertex *prev = ctx->latest_v->prev;
+ free(ctx->latest_v);
+ ctx->latest_v = prev;
+ }
+
+ while (ctx->latest_t) {
+ Triangle *prev = ctx->latest_t->prev;
+ free(ctx->latest_t);
+ ctx->latest_t = prev;
+ }
+
+ destroy_tess_context(ctx);
+}
+
+jint Java_org_oscim_renderer_sublayers_MeshLayer_tessGetCoordinates(JNIEnv *env, jclass c,
+ jlong ptr_context, jshortArray obj_coords, jfloat scale) {
+
+ TessContext *ctx = CAST_CTX(ptr_context);
+
+ int length = (*env)->GetArrayLength(env, obj_coords);
+
+ jshort* coords = (jshort*) (*env)->GetPrimitiveArrayCritical(env, obj_coords, 0);
+ if (coords == NULL) {
+ return 0;
+ }
+
+ int n_verts = 1 + ctx->latest_v->index;
+ int n_tris_copy = ctx->n_tris;
+
+ int cnt = 0;
+ for (; ctx->latest_v && cnt < length; cnt += 2) {
+ coords[cnt + 0] = (ctx->latest_v->pt[0] * scale) + 0.5f;
+ coords[cnt + 1] = (ctx->latest_v->pt[1] * scale) + 0.5f;
+ Vertex *prev = ctx->latest_v->prev;
+ free(ctx->latest_v);
+ ctx->latest_v = prev;
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_coords, coords, JNI_ABORT);
+
+ return cnt;
+}
+
+jint Java_org_oscim_renderer_sublayers_MeshLayer_tessGetIndices(JNIEnv *env, jclass c,
+ jlong ptr_context, jshortArray obj_indices) {
+
+ TessContext *ctx = CAST_CTX(ptr_context);
+
+ int length = (*env)->GetArrayLength(env, obj_indices);
+
+ jshort* tris = (jshort*) (*env)->GetPrimitiveArrayCritical(env, obj_indices, 0);
+ if (tris == NULL) {
+ return 0;
+ }
+
+ int n_tris_copy = ctx->n_tris;
+
+ int cnt = 0;
+
+ for (; ctx->latest_t && cnt < length; cnt += 3) {
+ tris[cnt + 0] = ctx->latest_t->v[0];
+ tris[cnt + 1] = ctx->latest_t->v[1];
+ tris[cnt + 2] = ctx->latest_t->v[2];
+ Triangle *prev = ctx->latest_t->prev;
+
+ free(ctx->latest_t);
+ ctx->latest_t = prev;
+ n_tris_copy--;
+ }
+
+ ctx->n_tris = n_tris_copy;
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_indices, tris, JNI_ABORT);
+
+ return cnt;
+}
+
+jlong Java_org_oscim_renderer_sublayers_MeshLayer_tessellate(JNIEnv *env, jclass c,
+ jfloatArray obj_points, jint pos,
+ jshortArray obj_index, jint ipos,
+ jint num_rings) { //, jintArray obj_out) {
+
+ jboolean isCopy;
+
+ printf("add %d %d %d\n", pos, ipos, num_rings);
+
+ float* orig_points = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_points, &isCopy);
+ if (orig_points == NULL)
+ return 0;
+
+ const float *points = orig_points + pos;
+
+ jshort* orig_indices = (jshort*) (*env)->GetPrimitiveArrayCritical(env, obj_index, &isCopy);
+ if (orig_indices == NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_points, orig_points, JNI_ABORT);
+ return 0;
+ }
+
+ jshort* indices = orig_indices + ipos;
+
+ const float **rings = malloc(sizeof(float*) * (num_rings + 1));
+ int offset = 0;
+ for (int i = 0; i < num_rings; i++) {
+ rings[i] = points + offset;
+ offset += indices[i];
+ }
+ rings[num_rings] = points + offset;
+
+ int nverts, ntris;
+
+ TessContext *ctx = tessellate(&nverts, &ntris,
+ rings, rings + (num_rings + 1));
+
+ free(rings);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_index, orig_indices, JNI_ABORT);
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_points, orig_points, JNI_ABORT);
+
+ return (long) ctx;
+}
diff --git a/vtm/jni/tessellate/tessellate.h b/vtm/jni/tessellate/tessellate.h
new file mode 100644
index 00000000..e1ca013d
--- /dev/null
+++ b/vtm/jni/tessellate/tessellate.h
@@ -0,0 +1,13 @@
+typedef struct Vertex {
+ double pt[3];
+ int index;
+ struct Vertex *prev;
+} Vertex;
+
+//void tessellate
+// (double **verts,
+// int *nverts,
+// int **tris,
+// int *ntris,
+// const float **contoursbegin,
+// const float **contoursend);
diff --git a/vtm/jni/tessellate/tessmono.c b/vtm/jni/tessellate/tessmono.c
new file mode 100644
index 00000000..4d084400
--- /dev/null
+++ b/vtm/jni/tessellate/tessmono.c
@@ -0,0 +1,201 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#include "gluos.h"
+#include
+#include "geom.h"
+#include "mesh.h"
+#include "tessmono.h"
+#include
+
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * The basic idea is explained in Preparata and Shamos (which I don''t
+ * have handy right now), although their implementation is more
+ * complicated than this one. The are two edge chains, an upper chain
+ * and a lower chain. We process all vertices from both chains in order,
+ * from right to left.
+ *
+ * The algorithm ensures that the following invariant holds after each
+ * vertex is processed: the untessellated region consists of two
+ * chains, where one chain (say the upper) is a single edge, and
+ * the other chain is concave. The left vertex of the single edge
+ * is always to the left of all vertices in the concave chain.
+ *
+ * Each step consists of adding the rightmost unprocessed vertex to one
+ * of the two chains, and forming a fan of triangles from the rightmost
+ * of two chain endpoints. Determining whether we can add each triangle
+ * to the fan is a simple orientation test. By making the fan as large
+ * as possible, we restore the invariant (check it yourself).
+ */
+int __gl_meshTessellateMonoRegion( GLUface *face )
+{
+ GLUhalfEdge *up, *lo;
+
+ /* All edges are oriented CCW around the boundary of the region.
+ * First, find the half-edge whose origin vertex is rightmost.
+ * Since the sweep goes from left to right, face->anEdge should
+ * be close to the edge we want.
+ */
+ up = face->anEdge;
+ assert( up->Lnext != up && up->Lnext->Lnext != up );
+
+ for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
+ ;
+ for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
+ ;
+ lo = up->Lprev;
+
+ while( up->Lnext != lo ) {
+ if( VertLeq( up->Dst, lo->Org )) {
+ /* up->Dst is on the left. It is safe to form triangles from lo->Org.
+ * The EdgeGoesLeft test guarantees progress even when some triangles
+ * are CW, given that the upper and lower chains are truly monotone.
+ */
+ while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
+ || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+ lo = lo->Lprev;
+ } else {
+ /* lo->Org is on the left. We can make CCW triangles from up->Dst. */
+ while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
+ || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
+ if (tempHalfEdge == NULL) return 0;
+ up = tempHalfEdge->Sym;
+ }
+ up = up->Lnext;
+ }
+ }
+
+ /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
+ * can be tessellated in a fan from this leftmost vertex.
+ */
+ assert( lo->Lnext != up );
+ while( lo->Lnext->Lnext != up ) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ */
+int __gl_meshTessellateInterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Make sure we don''t try to tessellate the new triangles. */
+ next = f->next;
+ if( f->inside ) {
+ if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ */
+void __gl_meshDiscardExterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Since f will be destroyed, save its next pointer. */
+ next = f->next;
+ if( ! f->inside ) {
+ __gl_meshZapFace( f );
+ }
+ }
+}
+
+#define MARKED_FOR_DELETION 0x7fffffff
+
+/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary )
+{
+ GLUhalfEdge *e, *eNext;
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ eNext = e->next;
+ if( e->Rface->inside != e->Lface->inside ) {
+
+ /* This is a boundary edge (one side is interior, one is exterior). */
+ e->winding = (e->Lface->inside) ? value : -value;
+ } else {
+
+ /* Both regions are interior, or both are exterior. */
+ if( ! keepOnlyBoundary ) {
+ e->winding = 0;
+ } else {
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ }
+ return 1;
+}
diff --git a/vtm/jni/tessellate/tessmono.h b/vtm/jni/tessellate/tessmono.h
new file mode 100644
index 00000000..8ee1b2fe
--- /dev/null
+++ b/vtm/jni/tessellate/tessmono.h
@@ -0,0 +1,71 @@
+/*
+ * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+ * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice including the dates of first publication and
+ * either this permission notice or a reference to
+ * http://oss.sgi.com/projects/FreeB/
+ * shall be included in all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Silicon Graphics, Inc.
+ * shall not be used in advertising or otherwise to promote the sale, use or
+ * other dealings in this Software without prior written authorization from
+ * Silicon Graphics, Inc.
+ */
+/*
+** Author: Eric Veach, July 1994.
+**
+*/
+
+#ifndef __tessmono_h_
+#define __tessmono_h_
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ *
+ * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ *
+ * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+
+int __gl_meshTessellateMonoRegion( GLUface *face );
+int __gl_meshTessellateInterior( GLUmesh *mesh );
+void __gl_meshDiscardExterior( GLUmesh *mesh );
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary );
+
+#endif
diff --git a/vtm/jni/triangle/README b/vtm/jni/triangle/README
new file mode 100644
index 00000000..b33ea009
--- /dev/null
+++ b/vtm/jni/triangle/README
@@ -0,0 +1,198 @@
+Triangle
+A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.
+Version 1.6
+
+Show Me
+A Display Program for Meshes and More.
+Version 1.6
+
+Copyright 1993, 1995, 1997, 1998, 2002, 2005 Jonathan Richard Shewchuk
+2360 Woolsey #H
+Berkeley, California 94705-1927
+Please send bugs and comments to jrs@cs.berkeley.edu
+
+Created as part of the Quake project (tools for earthquake simulation).
+Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
+There is no warranty whatsoever. Use at your own risk.
+
+
+Triangle generates exact Delaunay triangulations, constrained Delaunay
+triangulations, conforming Delaunay triangulations, Voronoi diagrams, and
+high-quality triangular meshes. The latter can be generated with no small
+or large angles, and are thus suitable for finite element analysis.
+Show Me graphically displays the contents of the geometric files used by
+Triangle. Show Me can also write images in PostScript form.
+
+Information on the algorithms used by Triangle, including complete
+references, can be found in the comments at the beginning of the triangle.c
+source file. Another listing of these references, with PostScript copies
+of some of the papers, is available from the Web page
+
+ http://www.cs.cmu.edu/~quake/triangle.research.html
+
+------------------------------------------------------------------------------
+
+These programs may be freely redistributed under the condition that the
+copyright notices (including the copy of this notice in the code comments
+and the copyright notice printed when the `-h' switch is selected) are
+not removed, and no compensation is received. Private, research, and
+institutional use is free. You may distribute modified versions of this
+code UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT
+IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH
+SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND
+CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as
+part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT
+WITH THE AUTHOR. (If you are not directly supplying this code to a
+customer, and you are instead telling them how they can obtain it for
+free, then you are not required to make any arrangement with me.)
+
+------------------------------------------------------------------------------
+
+The files included in this distribution are:
+
+ README The file you're reading now.
+ triangle.c Complete C source code for Triangle.
+ showme.c Complete C source code for Show Me.
+ triangle.h Include file for calling Triangle from another program.
+ tricall.c Sample program that calls Triangle.
+ makefile Makefile for compiling Triangle and Show Me.
+ A.poly A sample input file.
+
+Each of Triangle and Show Me is a single portable C file. The easiest way
+to compile them is to edit and use the included makefile. Before
+compiling, read the makefile, which describes your options, and edit it
+accordingly. You should specify:
+
+ The source and binary directories.
+
+ The C compiler and level of optimization.
+
+ The "correct" directories for include files (especially X include files),
+ if necessary.
+
+ Do you want single precision or double? (The default is double.) Do you
+ want to leave out some of Triangle's features to reduce the size of the
+ executable file? Investigate the SINGLE, REDUCED, and CDT_ONLY symbols.
+
+ If yours is not a Unix system, define the NO_TIMER symbol to remove the
+ Unix-specific timing code. Also, don't try to compile Show Me; it only
+ works with X Windows.
+
+ If you are compiling on an Intel x86 CPU and using gcc w/Linux or
+ Microsoft C, be sure to define the LINUX or CPU86 (for Microsoft) symbol
+ during compilation so that the exact arithmetic works right.
+
+Once you've done this, type "make" to compile the programs. Alternatively,
+the files are usually easy to compile without a makefile:
+
+ cc -O -o triangle triangle.c -lm
+ cc -O -o showme showme.c -lX11
+
+On some systems, the C compiler won't be able to find the X include files
+or libraries, and you'll need to specify an include path or library path:
+
+ cc -O -I/usr/local/include -o showme showme.c -L/usr/local/lib -lX11
+
+Some processors, including Intel x86 family and possibly Motorola 68xxx
+family chips, are IEEE conformant but have extended length internal
+floating-point registers that may defeat Triangle's exact arithmetic
+routines by failing to cause enough roundoff error! Typically, there is a
+way to set these internal registers so that they are rounded off to IEEE
+single or double precision format. I believe (but I'm not certain) that
+Triangle has the right incantations for x86 chips, if you have gcc running
+under Linux (define the LINUX compiler symbol) or Microsoft C (define the
+CPU86 compiler symbol).
+
+If you have a different processor or operating system, or if I got the
+incantations wrong, you should check your C compiler or system manuals to
+find out how to configure these internal registers to the precision you are
+using. Otherwise, the exact arithmetic routines won't be exact at all.
+See http://www.cs.cmu.edu/~quake/robust.pc.html for details. Triangle's
+exact arithmetic hasn't a hope of working on machines like the Cray C90 or
+Y-MP, which are not IEEE conformant and have inaccurate rounding.
+
+Triangle and Show Me have both text and HTML documentation. The latter is
+illustrated. Find it on the Web at
+
+ http://www.cs.cmu.edu/~quake/triangle.html
+ http://www.cs.cmu.edu/~quake/showme.html
+
+Complete text instructions are printed by invoking each program with the
+`-h' switch:
+
+ triangle -h
+ showme -h
+
+The instructions are long; you'll probably want to pipe the output to
+`more' or `lpr' or redirect it to a file.
+
+Both programs give a short list of command line options if they are invoked
+without arguments (that is, just type `triangle' or `showme').
+
+Try out Triangle on the enclosed sample file, A.poly:
+
+ triangle -p A
+ showme A.poly &
+
+Triangle will read the Planar Straight Line Graph defined by A.poly, and
+write its constrained Delaunay triangulation to A.1.node and A.1.ele.
+Show Me will display the figure defined by A.poly. There are two buttons
+marked "ele" in the Show Me window; click on the top one. This will cause
+Show Me to load and display the triangulation.
+
+For contrast, try running
+
+ triangle -pq A
+
+Now, click on the same "ele" button. A new triangulation will be loaded;
+this one having no angles smaller than 20 degrees.
+
+To see a Voronoi diagram, try this:
+
+ cp A.poly A.node
+ triangle -v A
+
+Click the "ele" button again. You will see the Delaunay triangulation of
+the points in A.poly, without the segments. Now click the top "voro" button.
+You will see the Voronoi diagram corresponding to that Delaunay triangulation.
+Click the "Reset" button to see the full extent of the diagram.
+
+------------------------------------------------------------------------------
+
+If you wish to call Triangle from another program, instructions for doing
+so are contained in the file `triangle.h' (but read Triangle's regular
+instructions first!). Also look at `tricall.c', which provides an example
+of how to call Triangle.
+
+Type "make trilibrary" to create triangle.o, a callable object file.
+Alternatively, the object file is usually easy to compile without a
+makefile:
+
+ cc -DTRILIBRARY -O -c triangle.c
+
+Type "make distclean" to remove all the object and executable files created
+by make.
+
+------------------------------------------------------------------------------
+
+If you use Triangle, and especially if you use it to accomplish real work,
+I would like very much to hear from you. A short letter or email (to
+jrs@cs.berkeley.edu) describing how you use Triangle will mean a lot to me.
+The more people I know are using this program, the more easily I can
+justify spending time on improvements and on the three-dimensional
+successor to Triangle, which in turn will benefit you. Also, I can put you
+on a list to receive email whenever a new version of Triangle is available.
+
+If you use a mesh generated by Triangle or plotted by Show Me in a
+publication, please include an acknowledgment as well. And please spell
+Triangle with a capital `T'! If you want to include a citation, use
+`Jonathan Richard Shewchuk, ``Triangle: Engineering a 2D Quality Mesh
+Generator and Delaunay Triangulator,'' in Applied Computational Geometry:
+Towards Geometric Engineering (Ming C. Lin and Dinesh Manocha, editors),
+volume 1148 of Lecture Notes in Computer Science, pages 203-222,
+Springer-Verlag, Berlin, May 1996. (From the First ACM Workshop on Applied
+Computational Geometry.)'
+
+
+Jonathan Richard Shewchuk
+July 27, 2005
diff --git a/vtm/jni/triangle/TriangleJni.c b/vtm/jni/triangle/TriangleJni.c
new file mode 100644
index 00000000..56721f3a
--- /dev/null
+++ b/vtm/jni/triangle/TriangleJni.c
@@ -0,0 +1,308 @@
+#include
+#include
+#include
+#include
+#include
+#include "triangle.h"
+
+#ifdef __ANDROID__
+#include
+#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "Triangle", __VA_ARGS__)
+#endif
+
+// from www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
+#if 0
+int pnpoly(int nvert, float *vert, float testx, float testy)
+{
+ int i, j, c = 0;
+ for (i = 0, j = (nvert-1)*2; i < nvert * 2; j = i++)
+ {
+ if ( ((vert[i*2+1] > testy) != (vert[j*j+1] > testy)) &&
+ (testx < (vert[j*2]-vert[i*2])
+ * (testy - vert[i*2+1])
+ / (vert[j*2+1]-vert[i*2+1]) + vert[i*2]) )
+ c = !c;
+ }
+ return c;
+}
+
+int compare_dups(const void *a, const void *b) {
+ int da = *((const long*) a);
+ int db = *((const long*) b);
+ return (da > db) - (da < db);
+}
+
+void shiftSegment(TriangleIO *in, int *seg, int pos) {
+ int size = (in->numberofsegments - pos - 1) * sizeof(int) * 2;
+ printf("shift %d - %d %d\n", size, in->numberofsegments, pos);
+ if (size > 0)
+ memmove(seg, seg + 2, size);
+
+ in->numberofsegments -= 1;
+}
+struct {
+ int p1;
+ int p2;
+} segment;
+
+#endif
+
+static void printPoly(TriangleIO *in) {
+ // print poly format to check with triangle/showme
+ printf("%d 2 0 0\n", in->numberofpoints);
+ for (int j = 0; j < in->numberofpoints; j++)
+ printf("%d %f %f\n", j, in->pointlist[j*2], in->pointlist[j*2+1]);
+
+ int *seg = in->segmentlist;
+ printf("%d 0\n", in->numberofsegments);
+ for (int j = 0; j < in->numberofsegments; j++, seg += 2)
+ printf("%d %d %d\n", j, *seg, *(seg+1));
+
+ printf("%d 0\n", in->numberofholes);
+ for (int j = 0; j < in->numberofholes; j++) {
+ printf("%d %f %f\n", j, in->holelist[j*2], in->holelist[j*2+1]);
+ }
+}
+
+jint Java_org_oscim_renderer_sublayers_ExtrusionLayer_triangulate(JNIEnv *env, jclass c,
+ jfloatArray obj_points, jint pos, jint len, jint num_rings, jobject indice_buf, jint offset) {
+
+ jshort* indices = (jshort*) (*env)->GetDirectBufferAddress(env, indice_buf);
+ jboolean isCopy;
+
+ float* orig_points = (float*) (*env)->GetPrimitiveArrayCritical(env, obj_points, &isCopy);
+ if (orig_points == NULL)
+ return 0;
+
+ float *points = orig_points + pos;
+
+ TriangleIO in, out;
+
+ memset(&in, 0, sizeof(TriangleIO));
+
+ in.numberofpoints = len >> 1;
+ in.pointlist = (float *) points;
+
+ // check if explicitly closed
+ if (in.pointlist[0] == in.pointlist[indices[0] - 2]
+ && in.pointlist[1] == in.pointlist[indices[0] - 1]) {
+ int point = 0;
+ for (int i = 0; i < num_rings; i++) {
+ // remove last point in ring
+ indices[i] -= 2;
+ int last = point + (indices[i] >> 1);
+
+ if (in.numberofpoints - last > 1)
+ memmove(in.pointlist + (last * 2), in.pointlist + ((last + 1) * 2),
+ (in.numberofpoints - last - 1) * 2 * sizeof(float));
+
+ in.numberofpoints--;
+ point = last;
+ }
+ }
+
+ int dups = 0;
+
+ float *i_points = points;
+ int *skip_list = NULL;
+
+ // check for duplicate vertices and keep a list
+ // of dups and the first occurence
+ for (int i = 0; i < in.numberofpoints - 1; i++) {
+ float x = *i_points++;
+ float y = *i_points++;
+ float *j_points = i_points;
+
+ for (int j = i + 1; j < in.numberofpoints; j++, j_points += 2) {
+ if ((*j_points == x) && (*(j_points + 1) == y)) {
+ skip_list = realloc(skip_list, (dups + 2) * 2 * sizeof(int));
+ skip_list[dups * 2 + 0] = j;
+ skip_list[dups * 2 + 1] = i;
+ dups++;
+ }
+ }
+ }
+
+ in.segmentlist = (int *) malloc(in.numberofpoints * 2 * sizeof(int));
+ in.numberofsegments = in.numberofpoints;
+ in.numberofholes = num_rings - 1;
+
+ int *rings = NULL;
+ if (in.numberofholes > 0) {
+ in.holelist = (float *) malloc(in.numberofholes * 2 * sizeof(float));
+ rings = (int*) malloc(num_rings * sizeof(int));
+ }
+
+ int *seg = in.segmentlist;
+ float *hole = in.holelist;
+
+ // counter going through all points
+ int point;
+ // counter going through all rings
+ int ring;
+
+ // assign all points to segments for each ring
+ for (ring = 0, point = 0; ring < num_rings; ring++, point++) {
+ int len;
+ int num_points = indices[ring] >> 1;
+
+ if (rings)
+ rings[ring] = num_points;
+
+ // add holes: we need a point inside the hole...
+ // this is just a heuristic, assuming that two
+ // 'parallel' lines have a distance of at least
+ // 1 unit. you'll notice when things went wrong
+ // when the hole is rendered instead of the poly
+ if (ring > 0) {
+ int k = point * 2;
+
+ float nx = in.pointlist[k++];
+ float ny = in.pointlist[k++];
+
+ float cx = 0, cy = 0, vx = 0, vy = 0;
+
+ // try to find a large enough segment
+ for (len = (point + num_points) * 2; k < len;) {
+ cx = nx;
+ cy = ny;
+
+ nx = in.pointlist[k++];
+ ny = in.pointlist[k++];
+
+ vx = nx - cx;
+ vy = ny - cy;
+
+ if (vx > 4 || vx < -4 || vy > 4 || vy < -4)
+ break;
+ }
+
+ float a = sqrt(vx * vx + vy * vy);
+
+ float ux = -vy / a;
+ float uy = vx / a;
+
+ float centerx = cx + vx / 2.0 - (ux * 0.1);
+ float centery = cy + vy / 2.0 - (uy * 0.1);
+
+ *hole++ = centerx;
+ *hole++ = centery;
+ }
+
+ // close ring
+ int last = point + (num_points - 1);
+ *seg++ = last;
+ *seg++ = point;
+
+ for (len = point + num_points - 1; point < len; point++) {
+ *seg++ = point;
+ *seg++ = point + 1;
+ }
+ }
+
+ if (dups) {
+ for (int i = 0; i < dups; i++) {
+ printf("duplicate points at %d, %d: %f,%f\n",
+ skip_list[i*2], skip_list[i*2+1],
+ in.pointlist[skip_list[i*2+1]*2],
+ in.pointlist[skip_list[i*2+1]*2+1]);
+ }
+ printPoly(&in);
+
+ // replace duplicate positions with first occurence
+ for (int i = 0; i < dups; i++) {
+ // position of the duplicate vertex
+ int pos = skip_list[i * 2] - i;
+ // first vertex
+ int replacement = skip_list[i * 2 + 1];
+
+ seg = in.segmentlist;
+ for (int j = 0; j < in.numberofsegments * 2; j++, seg++) {
+ if (*seg == pos) {
+ printf("%d: %d <- %d", j, pos, replacement);
+ *seg = replacement;
+ }
+ }
+ }
+ }
+
+ memset(&out, 0, sizeof(TriangleIO));
+ out.trianglelist = (INDICE*) indices;
+
+ // p - use polygon input, for CDT
+ // z - zero offset array offsets...
+ // P - no poly output
+ // N - no node output
+ // B - no bound output
+ // Q - be quiet!
+
+ TriangleOptions opt;
+ memset(&opt, 0, sizeof(TriangleOptions));
+
+ opt.dwyer = 1;
+ opt.steiner = -1;
+ opt.order = 1;
+ opt.maxarea = -1.0;
+
+ opt.poly = 1;
+ opt.usesegments = 1;
+ opt.nopolywritten = 1;
+ opt.nonodewritten = 1;
+ opt.nobound = 1;
+ opt.quiet = 1;
+
+ triangulate(&opt, &in, &out, (TriangleIO *) NULL);
+
+ if (in.numberofpoints < out.numberofpoints) {
+ // TODO rerun with 'nonodewritten = 0'
+ printf( "polygon input is bad! points in:%d out%d\n", in.numberofpoints, out.numberofpoints);
+ out.numberoftriangles = 0;
+ }
+ else if (out.trianglelist)
+ {
+ // scale to stride and add offset
+ short stride = 2;
+
+ if (offset < 0)
+ offset = 0;
+
+ INDICE *tri = out.trianglelist;
+
+ for (int n = out.numberoftriangles * 3; n > 0; n--, tri++)
+ *tri = *tri * stride + offset;
+
+ // when a ring has an odd number of points one (or rather two)
+ // additional vertices will be added. so the following rings
+ // needs extra offset...
+ int start = offset;
+ for (int j = 0, m = in.numberofholes; j < m; j++) {
+ start += rings[j] * stride;
+
+ // even number of points?
+ if (!(rings[j] & 1))
+ continue;
+
+ tri = out.trianglelist;
+ int n = out.numberoftriangles * 3;
+
+ for (; n-- > 0; tri++)
+ if (*tri >= start)
+ *tri += stride;
+
+ start += stride;
+ }
+ }
+ else
+ {
+ printf( "triangle failed %d\n", out.numberofpoints);
+ }
+
+ (*env)->ReleasePrimitiveArrayCritical(env, obj_points, orig_points, JNI_ABORT);
+
+ free(in.segmentlist);
+ free(in.holelist);
+ free(rings);
+ free(skip_list);
+
+ return out.numberoftriangles;
+}
diff --git a/vtm/jni/triangle/triangle.c b/vtm/jni/triangle/triangle.c
new file mode 100644
index 00000000..c4e1a3ca
--- /dev/null
+++ b/vtm/jni/triangle/triangle.c
@@ -0,0 +1,7390 @@
+/*****************************************************************************/
+/* */
+/* 888888888 ,o, / 888 */
+/* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */
+/* 888 888 888 88b 888 888 888 888 888 d888 88b */
+/* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */
+/* 888 888 888 C888 888 888 888 / 888 q888 */
+/* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */
+/* "8oo8D */
+/* */
+/* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */
+/* (triangle.c) */
+/* */
+/* Version 1.6 */
+/* July 28, 2005 */
+/* */
+/* Copyright 1993, 1995, 1997, 1998, 2002, 2005 */
+/* Jonathan Richard Shewchuk */
+/* 2360 Woolsey #H */
+/* Berkeley, California 94705-1927 */
+/* jrs@cs.berkeley.edu */
+/* */
+/* This program may be freely redistributed under the condition that the */
+/* copyright notices (including this entire header and the copyright */
+/* notice printed when the `-h' switch is selected) are not removed, and */
+/* no compensation is received. Private, research, and institutional */
+/* use is free. You may distribute modified versions of this code UNDER */
+/* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */
+/* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */
+/* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */
+/* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */
+/* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */
+/* WITH THE AUTHOR. (If you are not directly supplying this code to a */
+/* customer, and you are instead telling them how they can obtain it for */
+/* free, then you are not required to make any arrangement with me.) */
+/* */
+/* Hypertext instructions for Triangle are available on the Web at */
+/* */
+/* http://www.cs.cmu.edu/~quake/triangle.html */
+/* */
+/* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */
+/* whatsoever. This code is provided "as-is". Use at your own risk. */
+/* */
+/* Some of the references listed below are marked with an asterisk. [*] */
+/* These references are available for downloading from the Web page */
+/* */
+/* http://www.cs.cmu.edu/~quake/triangle.research.html */
+/* */
+/* Three papers discussing aspects of Triangle are available. A short */
+/* overview appears in "Triangle: Engineering a 2D Quality Mesh */
+/* Generator and Delaunay Triangulator," in Applied Computational */
+/* Geometry: Towards Geometric Engineering, Ming C. Lin and Dinesh */
+/* Manocha, editors, Lecture Notes in Computer Science volume 1148, */
+/* pages 203-222, Springer-Verlag, Berlin, May 1996 (from the First ACM */
+/* Workshop on Applied Computational Geometry). [*] */
+/* */
+/* The algorithms are discussed in the greatest detail in "Delaunay */
+/* Refinement Algorithms for Triangular Mesh Generation," Computational */
+/* Geometry: Theory and Applications 22(1-3):21-74, May 2002. [*] */
+/* */
+/* More detail about the data structures may be found in my dissertation: */
+/* "Delaunay Refinement Mesh Generation," Ph.D. thesis, Technical Report */
+/* CMU-CS-97-137, School of Computer Science, Carnegie Mellon University, */
+/* Pittsburgh, Pennsylvania, 18 May 1997. [*] */
+/* */
+/* Triangle was created as part of the Quake Project in the School of */
+/* Computer Science at Carnegie Mellon University. For further */
+/* information, see Hesheng Bao, Jacobo Bielak, Omar Ghattas, Loukas F. */
+/* Kallivokas, David R. O'Hallaron, Jonathan R. Shewchuk, and Jifeng Xu, */
+/* "Large-scale Simulation of Elastic Wave Propagation in Heterogeneous */
+/* Media on Parallel Computers," Computer Methods in Applied Mechanics */
+/* and Engineering 152(1-2):85-102, 22 January 1998. */
+/* */
+/* Triangle's Delaunay refinement algorithm for quality mesh generation is */
+/* a hybrid of one due to Jim Ruppert, "A Delaunay Refinement Algorithm */
+/* for Quality 2-Dimensional Mesh Generation," Journal of Algorithms */
+/* 18(3):548-585, May 1995 [*], and one due to L. Paul Chew, "Guaranteed- */
+/* Quality Mesh Generation for Curved Surfaces," Proceedings of the Ninth */
+/* Annual Symposium on Computational Geometry (San Diego, California), */
+/* pages 274-280, Association for Computing Machinery, May 1993, */
+/* http://portal.acm.org/citation.cfm?id=161150 . */
+/* */
+/* The Delaunay refinement algorithm has been modified so that it meshes */
+/* domains with small input angles well, as described in Gary L. Miller, */
+/* Steven E. Pav, and Noel J. Walkington, "When and Why Ruppert's */
+/* Algorithm Works," Twelfth International Meshing Roundtable, pages */
+/* 91-102, Sandia National Laboratories, September 2003. [*] */
+/* */
+/* My implementation of the divide-and-conquer and incremental Delaunay */
+/* triangulation algorithms follows closely the presentation of Guibas */
+/* and Stolfi, even though I use a triangle-based data structure instead */
+/* of their quad-edge data structure. (In fact, I originally implemented */
+/* Triangle using the quad-edge data structure, but the switch to a */
+/* triangle-based data structure sped Triangle by a factor of two.) The */
+/* mesh manipulation primitives and the two aforementioned Delaunay */
+/* triangulation algorithms are described by Leonidas J. Guibas and Jorge */
+/* Stolfi, "Primitives for the Manipulation of General Subdivisions and */
+/* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */
+/* 4(2):74-123, April 1985, http://portal.acm.org/citation.cfm?id=282923 .*/
+/* */
+/* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */
+/* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */
+/* Delaunay Triangulation," International Journal of Computer and */
+/* Information Science 9(3):219-242, 1980. Triangle's improvement of the */
+/* divide-and-conquer algorithm by alternating between vertical and */
+/* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */
+/* Conquer Algorithm for Constructing Delaunay Triangulations," */
+/* Algorithmica 2(2):137-151, 1987. */
+/* */
+/* The incremental insertion algorithm was first proposed by C. L. Lawson, */
+/* "Software for C1 Surface Interpolation," in Mathematical Software III, */
+/* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */
+/* For point location, I use the algorithm of Ernst P. Mucke, Isaac */
+/* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */
+/* Preprocessing in Two- and Three-Dimensional Delaunay Triangulations," */
+/* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */
+/* ACM, May 1996. [*] If I were to randomize the order of vertex */
+/* insertion (I currently don't bother), their result combined with the */
+/* result of Kenneth L. Clarkson and Peter W. Shor, "Applications of */
+/* Random Sampling in Computational Geometry II," Discrete & */
+/* Computational Geometry 4(1):387-421, 1989, would yield an expected */
+/* O(n^{4/3}) bound on running time. */
+/* */
+/* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */
+/* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */
+/* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */
+/* boundary of the triangulation are maintained in a splay tree for the */
+/* purpose of point location. Splay trees are described by Daniel */
+/* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */
+/* Trees," Journal of the ACM 32(3):652-686, July 1985, */
+/* http://portal.acm.org/citation.cfm?id=3835 . */
+/* */
+/* The algorithms for exact computation of the signs of determinants are */
+/* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */
+/* Point Arithmetic and Fast Robust Geometric Predicates," Discrete & */
+/* Computational Geometry 18(3):305-363, October 1997. (Also available */
+/* as Technical Report CMU-CS-96-140, School of Computer Science, */
+/* Carnegie Mellon University, Pittsburgh, Pennsylvania, May 1996.) [*] */
+/* An abbreviated version appears as Jonathan Richard Shewchuk, "Robust */
+/* Adaptive Floating-Point Geometric Predicates," Proceedings of the */
+/* Twelfth Annual Symposium on Computational Geometry, ACM, May 1996. [*] */
+/* Many of the ideas for my exact arithmetic routines originate with */
+/* Douglas M. Priest, "Algorithms for Arbitrary Precision Floating Point */
+/* Arithmetic," Tenth Symposium on Computer Arithmetic, pp. 132-143, IEEE */
+/* Computer Society Press, 1991. [*] Many of the ideas for the correct */
+/* evaluation of the signs of determinants are taken from Steven Fortune */
+/* and Christopher J. Van Wyk, "Efficient Exact Arithmetic for Computa- */
+/* tional Geometry," Proceedings of the Ninth Annual Symposium on */
+/* Computational Geometry, ACM, pp. 163-172, May 1993, and from Steven */
+/* Fortune, "Numerical Stability of Algorithms for 2D Delaunay Triangu- */
+/* lations," International Journal of Computational Geometry & Applica- */
+/* tions 5(1-2):193-213, March-June 1995. */
+/* */
+/* The method of inserting new vertices off-center (not precisely at the */
+/* circumcenter of every poor-quality triangle) is from Alper Ungor, */
+/* "Off-centers: A New Type of Steiner Points for Computing Size-Optimal */
+/* Quality-Guaranteed Delaunay Triangulations," Proceedings of LATIN */
+/* 2004 (Buenos Aires, Argentina), April 2004. */
+/* */
+/* For definitions of and results involving Delaunay triangulations, */
+/* constrained and conforming versions thereof, and other aspects of */
+/* triangular mesh generation, see the excellent survey by Marshall Bern */
+/* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */
+/* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */
+/* editors, World Scientific, Singapore, pp. 23-90, 1992. [*] */
+/* */
+/* The time for incrementally adding PSLG (planar straight line graph) */
+/* segments to create a constrained Delaunay triangulation is probably */
+/* O(t^2) per segment in the worst case and O(t) per segment in the */
+/* common case, where t is the number of triangles that intersect the */
+/* segment before it is inserted. This doesn't count point location, */
+/* which can be much more expensive. I could improve this to O(d log d) */
+/* time, but d is usually quite small, so it's not worth the bother. */
+/* (This note does not apply when the -s switch is used, invoking a */
+/* different method is used to insert segments.) */
+/* */
+/* The time for deleting a vertex from a Delaunay triangulation is O(d^2) */
+/* in the worst case and O(d) in the common case, where d is the degree */
+/* of the vertex being deleted. I could improve this to O(d log d) time, */
+/* but d is usually quite small, so it's not worth the bother. */
+/* */
+/* Ruppert's Delaunay refinement algorithm typically generates triangles */
+/* at a linear rate (constant time per triangle) after the initial */
+/* triangulation is formed. There may be pathological cases where */
+/* quadratic time is required, but these never arise in practice. */
+/* */
+/* The geometric predicates (circumcenter calculations, segment */
+/* intersection formulae, etc.) appear in my "Lecture Notes on Geometric */
+/* Robustness" at http://www.cs.berkeley.edu/~jrs/mesh . */
+/* */
+/* If you make any improvements to this code, please please please let me */
+/* know, so that I may obtain the improvements. Even if you don't change */
+/* the code, I'd still love to hear what it's being used for. */
+/* */
+/*****************************************************************************/
+
+#include "triangle_private.h"
+
+/* Fast lookup arrays to speed some of the mesh manipulation primitives. */
+
+int plus1mod3[3] = { 1, 2, 0 };
+int minus1mod3[3] = { 2, 0, 1 };
+
+/********* User-defined triangle evaluation routine begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* triunsuitable() Determine if a triangle is unsuitable, and thus must */
+/* be further refined. */
+/* */
+/* You may write your own procedure that decides whether or not a selected */
+/* triangle is too big (and needs to be refined). There are two ways to do */
+/* this. */
+/* */
+/* (1) Modify the procedure `triunsuitable' below, then recompile */
+/* Triangle. */
+/* */
+/* (2) Define the symbol EXTERNAL_TEST (either by adding the definition */
+/* to this file, or by using the appropriate compiler switch). This way, */
+/* you can compile triangle.c separately from your test. Write your own */
+/* `triunsuitable' procedure in a separate C file (using the same prototype */
+/* as below). Compile it and link the object code with triangle.o. */
+/* */
+/* This procedure returns 1 if the triangle is too large and should be */
+/* refined; 0 otherwise. */
+/* */
+/*****************************************************************************/
+
+#ifdef EXTERNAL_TEST
+
+int triunsuitable();
+
+#else /* not EXTERNAL_TEST */
+
+int triunsuitable(vertex triorg, vertex tridest, vertex triapex, REAL area) {
+ REAL dxoa, dxda, dxod;
+ REAL dyoa, dyda, dyod;
+ REAL oalen, dalen, odlen;
+ REAL maxlen;
+
+ dxoa = triorg[0] - triapex[0];
+ dyoa = triorg[1] - triapex[1];
+ dxda = tridest[0] - triapex[0];
+ dyda = tridest[1] - triapex[1];
+ dxod = triorg[0] - tridest[0];
+ dyod = triorg[1] - tridest[1];
+ /* Find the squares of the lengths of the triangle's three edges. */
+ oalen = dxoa * dxoa + dyoa * dyoa;
+ dalen = dxda * dxda + dyda * dyda;
+ odlen = dxod * dxod + dyod * dyod;
+ /* Find the square of the length of the longest edge. */
+ maxlen = (dalen > oalen) ? dalen : oalen;
+ maxlen = (odlen > maxlen) ? odlen : maxlen;
+
+ if (maxlen > 0.05 * (triorg[0] * triorg[0] + triorg[1] * triorg[1]) + 0.02) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+#endif /* not EXTERNAL_TEST */
+
+/** **/
+/** **/
+/********* User-defined triangle evaluation routine ends here *********/
+
+/********* Memory allocation and program exit wrappers begin here *********/
+/** **/
+/** **/
+
+void triexit(int status) {
+ printf("Exit %d.\n", status);
+
+ exit(status);
+}
+
+VOID *trimalloc(int size) {
+ VOID *memptr;
+
+ memptr = (VOID *) malloc((unsigned int) size);
+ if (memptr == (VOID *) NULL) {
+ printf("Error: Out of memory.\n");
+ triexit(1);
+ }
+ return (memptr);
+}
+
+void trifree(VOID *memptr) {
+ free(memptr);
+}
+
+/** **/
+/** **/
+/********* Memory allocation and program exit wrappers end here *********/
+
+/********* User interaction routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* internalerror() Ask the user to send me the defective product. Exit. */
+/* */
+/*****************************************************************************/
+
+int error_set = 0;
+void internalerror() {
+ error_set = 1;
+ printf("Triangle is going to quit its job now\n");
+ //printf(" Please report this bug to jrs@cs.berkeley.edu\n");
+ ///printf(" Include the message above, your input data set, and the exact\n");
+ //printf(" command line you used to run Triangle.\n");
+ //triexit(1);
+}
+
+/*****************************************************************************/
+/* */
+/* parsecommandline() Read the command line, identify switches, and set */
+/* up options and file names. */
+/* */
+/*****************************************************************************/
+
+void parsecommandline(int argc, char **argv, struct behavior *b) {
+ error_set = 0;
+
+#define STARTINDEX 0
+
+ int i, j;
+
+ b->poly = b->refine = b->quality = 0;
+ b->vararea = b->fixedarea = b->usertest = 0;
+ b->regionattrib = b->convex = b->weighted = b->jettison = 0;
+ b->firstnumber = 1;
+ b->edgesout = b->voronoi = b->neighbors = b->geomview = 0;
+ b->nobound = b->nopolywritten = b->nonodewritten = b->noelewritten = 0;
+ b->noiterationnum = 0;
+ b->noholes = b->noexact = 0;
+ b->incremental = b->sweepline = 0;
+ b->dwyer = 1;
+ b->splitseg = 0;
+ b->docheck = 0;
+ b->nobisect = 0;
+ b->conformdel = 0;
+ b->steiner = -1;
+ b->order = 1;
+ b->minangle = 0.0;
+ b->maxarea = -1.0;
+ b->quiet = b->verbose = 0;
+
+ for (i = STARTINDEX; i < argc; i++) {
+ for (j = STARTINDEX; argv[i][j] != '\0'; j++) {
+ if (argv[i][j] == 'p') {
+ b->poly = 1;
+ }
+#ifndef CDT_ONLY
+ if (argv[i][j] == 'r')
+ {
+ b->refine = 1;
+ }
+ if (argv[i][j] == 'q')
+ {
+ b->quality = 1;
+ if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ k = 0;
+ while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ j++;
+ workstring[k] = argv[i][j];
+ k++;
+ }
+ workstring[k] = '\0';
+ b->minangle = (REAL) strtod(workstring, (char **) NULL);
+ }
+ else
+ {
+ b->minangle = 20.0;
+ }
+ }
+ if (argv[i][j] == 'a')
+ {
+ b->quality = 1;
+ if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ b->fixedarea = 1;
+ k = 0;
+ while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) ||
+ (argv[i][j + 1] == '.'))
+ {
+ j++;
+ workstring[k] = argv[i][j];
+ k++;
+ }
+ workstring[k] = '\0';
+ b->maxarea = (REAL) strtod(workstring, (char **) NULL);
+ if (b->maxarea <= 0.0)
+ {
+ printf("Error: Maximum area must be greater than zero.\n");
+ triexit(1);
+ }
+ }
+ else
+ {
+ b->vararea = 1;
+ }
+ }
+ if (argv[i][j] == 'u')
+ {
+ b->quality = 1;
+ b->usertest = 1;
+ }
+#endif /* not CDT_ONLY */
+ if (argv[i][j] == 'A') {
+ b->regionattrib = 1;
+ }
+ if (argv[i][j] == 'c') {
+ b->convex = 1;
+ }
+ if (argv[i][j] == 'w') {
+ b->weighted = 1;
+ }
+ if (argv[i][j] == 'W') {
+ b->weighted = 2;
+ }
+ if (argv[i][j] == 'j') {
+ b->jettison = 1;
+ }
+ if (argv[i][j] == 'z') {
+ b->firstnumber = 0;
+ }
+ if (argv[i][j] == 'e') {
+ b->edgesout = 1;
+ }
+ if (argv[i][j] == 'v') {
+ b->voronoi = 1;
+ }
+ if (argv[i][j] == 'n') {
+ b->neighbors = 1;
+ }
+ if (argv[i][j] == 'g') {
+ b->geomview = 1;
+ }
+ if (argv[i][j] == 'B') {
+ b->nobound = 1;
+ }
+ if (argv[i][j] == 'P') {
+ b->nopolywritten = 1;
+ }
+ if (argv[i][j] == 'N') {
+ b->nonodewritten = 1;
+ }
+ if (argv[i][j] == 'E') {
+ b->noelewritten = 1;
+ }
+ if (argv[i][j] == 'O') {
+ b->noholes = 1;
+ }
+ if (argv[i][j] == 'X') {
+ b->noexact = 1;
+ }
+ if (argv[i][j] == 'o') {
+ if (argv[i][j + 1] == '2') {
+ j++;
+ b->order = 2;
+ }
+ }
+#ifndef CDT_ONLY
+ if (argv[i][j] == 'Y')
+ {
+ b->nobisect++;
+ }
+ if (argv[i][j] == 'S')
+ {
+ b->steiner = 0;
+ while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9'))
+ {
+ j++;
+ b->steiner = b->steiner * 10 + (int) (argv[i][j] - '0');
+ }
+ }
+#endif /* not CDT_ONLY */
+#ifndef REDUCED
+ if (argv[i][j] == 'i')
+ {
+ b->incremental = 1;
+ }
+ if (argv[i][j] == 'F')
+ {
+ b->sweepline = 1;
+ }
+#endif /* not REDUCED */
+ if (argv[i][j] == 'l') {
+ b->dwyer = 0;
+ }
+#ifndef REDUCED
+#ifndef CDT_ONLY
+ if (argv[i][j] == 's')
+ {
+ b->splitseg = 1;
+ }
+ if ((argv[i][j] == 'D') || (argv[i][j] == 'L'))
+ {
+ b->quality = 1;
+ b->conformdel = 1;
+ }
+#endif /* not CDT_ONLY */
+ if (argv[i][j] == 'C')
+ {
+ b->docheck = 1;
+ }
+#endif /* not REDUCED */
+ if (argv[i][j] == 'Q') {
+ b->quiet = 1;
+ }
+ if (argv[i][j] == 'V') {
+ b->verbose++;
+ }
+ }
+ }
+ b->usesegments = b->poly || b->refine || b->quality || b->convex;
+ b->goodangle = cos(b->minangle * PI / 180.0);
+ if (b->goodangle == 1.0) {
+ b->offconstant = 0.0;
+ }
+ else {
+ b->offconstant = 0.475 * sqrt((1.0 + b->goodangle) / (1.0 - b->goodangle));
+ }
+ b->goodangle *= b->goodangle;
+ if (b->refine && b->noiterationnum) {
+ printf( "Error: You cannot use the -I switch when refining a triangulation.\n");
+ triexit(1);
+ }
+ /* Be careful not to allocate space for element area constraints that */
+ /* will never be assigned any value (other than the default -1.0). */
+ if (!b->refine && !b->poly) {
+ b->vararea = 0;
+ }
+ /* Be careful not to add an extra attribute to each element unless the */
+ /* input supports it (PSLG in, but not refining a preexisting mesh). */
+ if (b->refine || !b->poly) {
+ b->regionattrib = 0;
+ }
+ /* Regular/weighted triangulations are incompatible with PSLGs */
+ /* and meshing. */
+ if (b->weighted && (b->poly || b->quality)) {
+ b->weighted = 0;
+ if (!b->quiet) {
+ printf("Warning: weighted triangulations (-w, -W) are incompatible\n");
+ printf(" with PSLGs (-p) and meshing (-q, -a, -u). Weights ignored.\n");
+ }
+ }
+ if (b->jettison && b->nonodewritten && !b->quiet) {
+ printf("Warning: -j and -N switches are somewhat incompatible.\n");
+ printf(" If any vertices are jettisoned, you will need the output\n");
+ printf(" .node file to reconstruct the new node indices.");
+ }
+}
+
+/** **/
+/** **/
+/********* User interaction routines begin here *********/
+
+/********* Memory management routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* poolzero() Set all of a pool's fields to zero. */
+/* */
+/* This procedure should never be called on a pool that has any memory */
+/* allocated to it, as that memory would leak. */
+/* */
+/*****************************************************************************/
+
+void poolzero(struct memorypool *pool) {
+ pool->firstblock = (VOID **) NULL;
+ pool->nowblock = (VOID **) NULL;
+ pool->nextitem = (VOID *) NULL;
+ pool->deaditemstack = (VOID *) NULL;
+ pool->pathblock = (VOID **) NULL;
+ pool->pathitem = (VOID *) NULL;
+ pool->alignbytes = 0;
+ pool->itembytes = 0;
+ pool->itemsperblock = 0;
+ pool->itemsfirstblock = 0;
+ pool->items = 0;
+ pool->maxitems = 0;
+ pool->unallocateditems = 0;
+ pool->pathitemsleft = 0;
+}
+
+/*****************************************************************************/
+/* */
+/* poolrestart() Deallocate all items in a pool. */
+/* */
+/* The pool is returned to its starting state, except that no memory is */
+/* freed to the operating system. Rather, the previously allocated blocks */
+/* are ready to be reused. */
+/* */
+/*****************************************************************************/
+
+void poolrestart(struct memorypool *pool) {
+ unsigned long alignptr;
+
+ pool->items = 0;
+ pool->maxitems = 0;
+
+ /* Set the currently active block. */
+ pool->nowblock = pool->firstblock;
+ /* Find the first item in the pool. Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->nowblock + 1);
+ /* Align the item on an `alignbytes'-byte boundary. */
+ pool->nextitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* There are lots of unallocated items left in this block. */
+ pool->unallocateditems = pool->itemsfirstblock;
+ /* The stack of deallocated items is empty. */
+ pool->deaditemstack = (VOID *) NULL;
+}
+
+/*****************************************************************************/
+/* */
+/* poolinit() Initialize a pool of memory for allocation of items. */
+/* */
+/* This routine initializes the machinery for allocating items. A `pool' */
+/* is created whose records have size at least `bytecount'. Items will be */
+/* allocated in `itemcount'-item blocks. Each item is assumed to be a */
+/* collection of words, and either pointers or floating-point values are */
+/* assumed to be the "primary" word type. (The "primary" word type is used */
+/* to determine alignment of items.) If `alignment' isn't zero, all items */
+/* will be `alignment'-byte aligned in memory. `alignment' must be either */
+/* a multiple or a factor of the primary word size; powers of two are safe. */
+/* `alignment' is normally used to create a few unused bits at the bottom */
+/* of each item's pointer, in which information may be stored. */
+/* */
+/* Don't change this routine unless you understand it. */
+/* */
+/*****************************************************************************/
+
+void poolinit(struct memorypool *pool, int bytecount, int itemcount, int firstitemcount,
+ int alignment) {
+ /* Find the proper alignment, which must be at least as large as: */
+ /* - The parameter `alignment'. */
+ /* - sizeof(VOID *), so the stack of dead items can be maintained */
+ /* without unaligned accesses. */
+ if (alignment > sizeof(VOID *)) {
+ pool->alignbytes = alignment;
+ }
+ else {
+ pool->alignbytes = sizeof(VOID *);
+ }
+ pool->itembytes = ((bytecount - 1) / pool->alignbytes + 1) * pool->alignbytes;
+ pool->itemsperblock = itemcount;
+ if (firstitemcount == 0) {
+ pool->itemsfirstblock = itemcount;
+ }
+ else {
+ pool->itemsfirstblock = firstitemcount;
+ }
+
+ /* Allocate a block of items. Space for `itemsfirstblock' items and one */
+ /* pointer (to point to the next block) are allocated, as well as space */
+ /* to ensure alignment of the items. */
+ pool->firstblock = (VOID **) trimalloc(
+ pool->itemsfirstblock * pool->itembytes + (int) sizeof(VOID *) + pool->alignbytes);
+ /* Set the next block pointer to NULL. */
+ *(pool->firstblock) = (VOID *) NULL;
+ poolrestart(pool);
+}
+
+/*****************************************************************************/
+/* */
+/* pooldeinit() Free to the operating system all memory taken by a pool. */
+/* */
+/*****************************************************************************/
+
+void pooldeinit(struct memorypool *pool) {
+ while (pool->firstblock != (VOID **) NULL) {
+ pool->nowblock = (VOID **) *(pool->firstblock);
+ trifree((VOID *) pool->firstblock);
+ pool->firstblock = pool->nowblock;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* poolalloc() Allocate space for an item. */
+/* */
+/*****************************************************************************/
+
+VOID *poolalloc(struct memorypool *pool) {
+ VOID *newitem;
+ VOID **newblock;
+ unsigned long alignptr;
+
+ /* First check the linked list of dead items. If the list is not */
+ /* empty, allocate an item from the list rather than a fresh one. */
+ if (pool->deaditemstack != (VOID *) NULL) {
+ newitem = pool->deaditemstack; /* Take first item in list. */
+ pool->deaditemstack = *(VOID **) pool->deaditemstack;
+ }
+ else {
+ /* Check if there are any free items left in the current block. */
+ if (pool->unallocateditems == 0) {
+ /* Check if another block must be allocated. */
+ if (*(pool->nowblock) == (VOID *) NULL) {
+ /* Allocate a new block of items, pointed to by the previous block. */
+ newblock = (VOID **) trimalloc(
+ pool->itemsperblock * pool->itembytes + (int) sizeof(VOID *) + pool->alignbytes);
+ *(pool->nowblock) = (VOID *) newblock;
+ /* The next block pointer is NULL. */
+ *newblock = (VOID *) NULL;
+ }
+
+ /* Move to the new block. */
+ pool->nowblock = (VOID **) *(pool->nowblock);
+ /* Find the first item in the block. */
+ /* Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->nowblock + 1);
+ /* Align the item on an `alignbytes'-byte boundary. */
+ pool->nextitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* There are lots of unallocated items left in this block. */
+ pool->unallocateditems = pool->itemsperblock;
+ }
+
+ /* Allocate a new item. */
+ newitem = pool->nextitem;
+ /* Advance `nextitem' pointer to next free item in block. */
+ pool->nextitem = (VOID *) ((char *) pool->nextitem + pool->itembytes);
+ pool->unallocateditems--;
+ pool->maxitems++;
+ }
+ pool->items++;
+ return newitem;
+}
+
+/*****************************************************************************/
+/* */
+/* pooldealloc() Deallocate space for an item. */
+/* */
+/* The deallocated space is stored in a queue for later reuse. */
+/* */
+/*****************************************************************************/
+
+void pooldealloc(struct memorypool *pool, VOID *dyingitem) {
+ /* Push freshly killed item onto stack. */
+ *((VOID **) dyingitem) = pool->deaditemstack;
+ pool->deaditemstack = dyingitem;
+ pool->items--;
+}
+
+/*****************************************************************************/
+/* */
+/* traversalinit() Prepare to traverse the entire list of items. */
+/* */
+/* This routine is used in conjunction with traverse(). */
+/* */
+/*****************************************************************************/
+
+void traversalinit(struct memorypool *pool) {
+ unsigned long alignptr;
+
+ /* Begin the traversal in the first block. */
+ pool->pathblock = pool->firstblock;
+ /* Find the first item in the block. Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->pathblock + 1);
+ /* Align with item on an `alignbytes'-byte boundary. */
+ pool->pathitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* Set the number of items left in the current block. */
+ pool->pathitemsleft = pool->itemsfirstblock;
+}
+
+/*****************************************************************************/
+/* */
+/* traverse() Find the next item in the list. */
+/* */
+/* This routine is used in conjunction with traversalinit(). Be forewarned */
+/* that this routine successively returns all items in the list, including */
+/* deallocated ones on the deaditemqueue. It's up to you to figure out */
+/* which ones are actually dead. Why? I don't want to allocate extra */
+/* space just to demarcate dead items. It can usually be done more */
+/* space-efficiently by a routine that knows something about the structure */
+/* of the item. */
+/* */
+/*****************************************************************************/
+
+VOID *traverse(struct memorypool *pool) {
+ VOID *newitem;
+ unsigned long alignptr;
+
+ /* Stop upon exhausting the list of items. */
+ if (pool->pathitem == pool->nextitem) {
+ return (VOID *) NULL;
+ }
+
+ /* Check whether any untraversed items remain in the current block. */
+ if (pool->pathitemsleft == 0) {
+ /* Find the next block. */
+ pool->pathblock = (VOID **) *(pool->pathblock);
+ /* Find the first item in the block. Increment by the size of (VOID *). */
+ alignptr = (unsigned long) (pool->pathblock + 1);
+ /* Align with item on an `alignbytes'-byte boundary. */
+ pool->pathitem = (VOID *) (alignptr + (unsigned long) pool->alignbytes
+ - (alignptr % (unsigned long) pool->alignbytes));
+ /* Set the number of items left in the current block. */
+ pool->pathitemsleft = pool->itemsperblock;
+ }
+
+ newitem = pool->pathitem;
+ /* Find the next item in the block. */
+ pool->pathitem = (VOID *) ((char *) pool->pathitem + pool->itembytes);
+ pool->pathitemsleft--;
+ return newitem;
+}
+
+/*****************************************************************************/
+/* */
+/* dummyinit() Initialize the triangle that fills "outer space" and the */
+/* omnipresent subsegment. */
+/* */
+/* The triangle that fills "outer space," called `dummytri', is pointed to */
+/* by every triangle and subsegment on a boundary (be it outer or inner) of */
+/* the triangulation. Also, `dummytri' points to one of the triangles on */
+/* the convex hull (until the holes and concavities are carved), making it */
+/* possible to find a starting triangle for point location. */
+/* */
+/* The omnipresent subsegment, `dummysub', is pointed to by every triangle */
+/* or subsegment that doesn't have a full complement of real subsegments */
+/* to point to. */
+/* */
+/* `dummytri' and `dummysub' are generally required to fulfill only a few */
+/* invariants: their vertices must remain NULL and `dummytri' must always */
+/* be bonded (at offset zero) to some triangle on the convex hull of the */
+/* mesh, via a boundary edge. Otherwise, the connections of `dummytri' and */
+/* `dummysub' may change willy-nilly. This makes it possible to avoid */
+/* writing a good deal of special-case code (in the edge flip, for example) */
+/* for dealing with the boundary of the mesh, places where no subsegment is */
+/* present, and so forth. Other entities are frequently bonded to */
+/* `dummytri' and `dummysub' as if they were real mesh entities, with no */
+/* harm done. */
+/* */
+/*****************************************************************************/
+
+void dummyinit(struct mesh *m, struct behavior *b, int trianglebytes, int subsegbytes) {
+ unsigned long alignptr;
+
+ /* Set up `dummytri', the `triangle' that occupies "outer space." */
+ m->dummytribase = (triangle *) trimalloc(trianglebytes + m->triangles.alignbytes);
+ /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */
+ alignptr = (unsigned long) m->dummytribase;
+ m->dummytri = (triangle *) (alignptr + (unsigned long) m->triangles.alignbytes
+ - (alignptr % (unsigned long) m->triangles.alignbytes));
+ /* Initialize the three adjoining triangles to be "outer space." These */
+ /* will eventually be changed by various bonding operations, but their */
+ /* values don't really matter, as long as they can legally be */
+ /* dereferenced. */
+ m->dummytri[0] = (triangle) m->dummytri;
+ m->dummytri[1] = (triangle) m->dummytri;
+ m->dummytri[2] = (triangle) m->dummytri;
+ /* Three NULL vertices. */
+ m->dummytri[3] = (triangle) NULL;
+ m->dummytri[4] = (triangle) NULL;
+ m->dummytri[5] = (triangle) NULL;
+
+ if (b->usesegments) {
+ /* Set up `dummysub', the omnipresent subsegment pointed to by any */
+ /* triangle side or subsegment end that isn't attached to a real */
+ /* subsegment. */
+ m->dummysubbase = (subseg *) trimalloc(subsegbytes + m->subsegs.alignbytes);
+ /* Align `dummysub' on a `subsegs.alignbytes'-byte boundary. */
+ alignptr = (unsigned long) m->dummysubbase;
+ m->dummysub = (subseg *) (alignptr + (unsigned long) m->subsegs.alignbytes
+ - (alignptr % (unsigned long) m->subsegs.alignbytes));
+ /* Initialize the two adjoining subsegments to be the omnipresent */
+ /* subsegment. These will eventually be changed by various bonding */
+ /* operations, but their values don't really matter, as long as they */
+ /* can legally be dereferenced. */
+ m->dummysub[0] = (subseg) m->dummysub;
+ m->dummysub[1] = (subseg) m->dummysub;
+ /* Four NULL vertices. */
+ m->dummysub[2] = (subseg) NULL;
+ m->dummysub[3] = (subseg) NULL;
+ m->dummysub[4] = (subseg) NULL;
+ m->dummysub[5] = (subseg) NULL;
+ /* Initialize the two adjoining triangles to be "outer space." */
+ m->dummysub[6] = (subseg) m->dummytri;
+ m->dummysub[7] = (subseg) m->dummytri;
+ /* Set the boundary marker to zero. */
+ *(int *) (m->dummysub + 8) = 0;
+
+ /* Initialize the three adjoining subsegments of `dummytri' to be */
+ /* the omnipresent subsegment. */
+ m->dummytri[6] = (triangle) m->dummysub;
+ m->dummytri[7] = (triangle) m->dummysub;
+ m->dummytri[8] = (triangle) m->dummysub;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* initializevertexpool() Calculate the size of the vertex data structure */
+/* and initialize its memory pool. */
+/* */
+/* This routine also computes the `vertexmarkindex' and `vertex2triindex' */
+/* indices used to find values within each vertex. */
+/* */
+/*****************************************************************************/
+
+void initializevertexpool(struct mesh *m, struct behavior *b) {
+ int vertexsize;
+
+ /* The index within each vertex at which the boundary marker is found, */
+ /* followed by the vertex type. Ensure the vertex marker is aligned to */
+ /* a sizeof(int)-byte address. */
+ m->vertexmarkindex = ((m->mesh_dim + m->nextras) * sizeof(REAL) + sizeof(int) - 1) / sizeof(int);
+ vertexsize = (m->vertexmarkindex + 2) * sizeof(int);
+ if (b->poly) {
+ /* The index within each vertex at which a triangle pointer is found. */
+ /* Ensure the pointer is aligned to a sizeof(triangle)-byte address. */
+ m->vertex2triindex = (vertexsize + sizeof(triangle) - 1) / sizeof(triangle);
+ vertexsize = (m->vertex2triindex + 1) * sizeof(triangle);
+ }
+
+ /* Initialize the pool of vertices. */
+ poolinit(&m->vertices, vertexsize, VERTEXPERBLOCK,
+ m->invertices > VERTEXPERBLOCK ? m->invertices : VERTEXPERBLOCK,
+ sizeof(REAL));
+}
+
+/*****************************************************************************/
+/* */
+/* initializetrisubpools() Calculate the sizes of the triangle and */
+/* subsegment data structures and initialize */
+/* their memory pools. */
+/* */
+/* This routine also computes the `highorderindex', `elemattribindex', and */
+/* `areaboundindex' indices used to find values within each triangle. */
+/* */
+/*****************************************************************************/
+
+void initializetrisubpools(struct mesh *m, struct behavior *b) {
+ int trisize;
+
+ /* The index within each triangle at which the extra nodes (above three) */
+ /* associated with high order elements are found. There are three */
+ /* pointers to other triangles, three pointers to corners, and possibly */
+ /* three pointers to subsegments before the extra nodes. */
+ m->highorderindex = 6 + (b->usesegments * 3);
+ /* The number of bytes occupied by a triangle. */
+ trisize = ((b->order + 1) * (b->order + 2) / 2 + (m->highorderindex - 3)) * sizeof(triangle);
+ /* The index within each triangle at which its attributes are found, */
+ /* where the index is measured in REALs. */
+ m->elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL);
+ /* The index within each triangle at which the maximum area constraint */
+ /* is found, where the index is measured in REALs. Note that if the */
+ /* `regionattrib' flag is set, an additional attribute will be added. */
+ m->areaboundindex = m->elemattribindex + m->eextras + b->regionattrib;
+ /* If triangle attributes or an area bound are needed, increase the number */
+ /* of bytes occupied by a triangle. */
+ if (b->vararea) {
+ trisize = (m->areaboundindex + 1) * sizeof(REAL);
+ }
+ else if (m->eextras + b->regionattrib > 0) {
+ trisize = m->areaboundindex * sizeof(REAL);
+ }
+ /* If a Voronoi diagram or triangle neighbor graph is requested, make */
+ /* sure there's room to store an integer index in each triangle. This */
+ /* integer index can occupy the same space as the subsegment pointers */
+ /* or attributes or area constraint or extra nodes. */
+ if ((b->voronoi || b->neighbors) && (trisize < 6 * sizeof(triangle) + sizeof(int))) {
+ trisize = 6 * sizeof(triangle) + sizeof(int);
+ }
+
+ /* Having determined the memory size of a triangle, initialize the pool. */
+ poolinit(&m->triangles, trisize, TRIPERBLOCK,
+ (2 * m->invertices - 2) > TRIPERBLOCK ? (2 * m->invertices - 2) : TRIPERBLOCK, 4);
+
+ if (b->usesegments) {
+ /* Initialize the pool of subsegments. Take into account all eight */
+ /* pointers and one boundary marker. */
+ poolinit(&m->subsegs, 8 * sizeof(triangle) + sizeof(int), SUBSEGPERBLOCK, SUBSEGPERBLOCK, 4);
+
+ /* Initialize the "outer space" triangle and omnipresent subsegment. */
+ dummyinit(m, b, m->triangles.itembytes, m->subsegs.itembytes);
+ }
+ else {
+ /* Initialize the "outer space" triangle. */
+ dummyinit(m, b, m->triangles.itembytes, 0);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* triangledealloc() Deallocate space for a triangle, marking it dead. */
+/* */
+/*****************************************************************************/
+
+void triangledealloc(struct mesh *m, triangle *dyingtriangle) {
+ /* Mark the triangle as dead. This makes it possible to detect dead */
+ /* triangles when traversing the list of all triangles. */
+ killtri(dyingtriangle);
+ pooldealloc(&m->triangles, (VOID *) dyingtriangle);
+}
+
+/*****************************************************************************/
+/* */
+/* triangletraverse() Traverse the triangles, skipping dead ones. */
+/* */
+/*****************************************************************************/
+
+triangle *triangletraverse(struct mesh *m) {
+ triangle *newtriangle;
+
+ do {
+ newtriangle = (triangle *) traverse(&m->triangles);
+ if (newtriangle == (triangle *) NULL) {
+ return (triangle *) NULL;
+ }
+ } while (deadtri(newtriangle)); /* Skip dead ones. */
+ return newtriangle;
+}
+
+/*****************************************************************************/
+/* */
+/* subsegdealloc() Deallocate space for a subsegment, marking it dead. */
+/* */
+/*****************************************************************************/
+
+void subsegdealloc(struct mesh *m, subseg *dyingsubseg) {
+ /* Mark the subsegment as dead. This makes it possible to detect dead */
+ /* subsegments when traversing the list of all subsegments. */
+ killsubseg(dyingsubseg);
+ pooldealloc(&m->subsegs, (VOID *) dyingsubseg);
+}
+
+/*****************************************************************************/
+/* */
+/* subsegtraverse() Traverse the subsegments, skipping dead ones. */
+/* */
+/*****************************************************************************/
+
+subseg *subsegtraverse(struct mesh *m) {
+ subseg *newsubseg;
+
+ do {
+ newsubseg = (subseg *) traverse(&m->subsegs);
+ if (newsubseg == (subseg *) NULL) {
+ return (subseg *) NULL;
+ }
+ } while (deadsubseg(newsubseg)); /* Skip dead ones. */
+ return newsubseg;
+}
+
+/*****************************************************************************/
+/* */
+/* vertexdealloc() Deallocate space for a vertex, marking it dead. */
+/* */
+/*****************************************************************************/
+
+void vertexdealloc(struct mesh *m, vertex dyingvertex) {
+ /* Mark the vertex as dead. This makes it possible to detect dead */
+ /* vertices when traversing the list of all vertices. */
+ setvertextype(dyingvertex, DEADVERTEX);
+ pooldealloc(&m->vertices, (VOID *) dyingvertex);
+}
+
+/*****************************************************************************/
+/* */
+/* vertextraverse() Traverse the vertices, skipping dead ones. */
+/* */
+/*****************************************************************************/
+
+vertex vertextraverse(struct mesh *m) {
+ vertex newvertex;
+
+ do {
+ newvertex = (vertex) traverse(&m->vertices);
+ if (newvertex == (vertex) NULL) {
+ return (vertex) NULL;
+ }
+ } while (vertextype(newvertex) == DEADVERTEX); /* Skip dead ones. */
+ return newvertex;
+}
+
+/*****************************************************************************/
+/* */
+/* getvertex() Get a specific vertex, by number, from the list. */
+/* */
+/* The first vertex is number 'firstnumber'. */
+/* */
+/* Note that this takes O(n) time (with a small constant, if VERTEXPERBLOCK */
+/* is large). I don't care to take the trouble to make it work in constant */
+/* time. */
+/* */
+/*****************************************************************************/
+
+vertex getvertex(struct mesh *m, struct behavior *b, int number) {
+ VOID **getblock;
+ char *foundvertex;
+ unsigned long alignptr;
+ int current;
+
+ getblock = m->vertices.firstblock;
+ current = b->firstnumber;
+
+ /* Find the right block. */
+ if (current + m->vertices.itemsfirstblock <= number) {
+ getblock = (VOID **) *getblock;
+ current += m->vertices.itemsfirstblock;
+ while (current + m->vertices.itemsperblock <= number) {
+ getblock = (VOID **) *getblock;
+ current += m->vertices.itemsperblock;
+ }
+ }
+
+ /* Now find the right vertex. */
+ alignptr = (unsigned long) (getblock + 1);
+ foundvertex = (char *) (alignptr + (unsigned long) m->vertices.alignbytes
+ - (alignptr % (unsigned long) m->vertices.alignbytes));
+ return (vertex) (foundvertex + m->vertices.itembytes * (number - current));
+}
+
+/*****************************************************************************/
+/* */
+/* triangledeinit() Free all remaining allocated memory. */
+/* */
+/*****************************************************************************/
+
+void triangledeinit(struct mesh *m, struct behavior *b) {
+ pooldeinit(&m->triangles);
+ trifree((VOID *) m->dummytribase);
+ if (b->usesegments) {
+ pooldeinit(&m->subsegs);
+ trifree((VOID *) m->dummysubbase);
+ }
+ pooldeinit(&m->vertices);
+#ifndef CDT_ONLY
+ if (b->quality)
+ {
+ pooldeinit(&m->badsubsegs);
+ if ((b->minangle > 0.0) || b->vararea || b->fixedarea || b->usertest)
+ {
+ pooldeinit(&m->badtriangles);
+ pooldeinit(&m->flipstackers);
+ }
+ }
+#endif /* not CDT_ONLY */
+}
+
+/** **/
+/** **/
+/********* Memory management routines end here *********/
+
+/********* Constructors begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* maketriangle() Create a new triangle with orientation zero. */
+/* */
+/*****************************************************************************/
+
+void maketriangle(struct mesh *m, struct behavior *b, struct otri *newotri) {
+ int i;
+
+ newotri->tri = (triangle *) poolalloc(&m->triangles);
+ /* Initialize the three adjoining triangles to be "outer space". */
+ newotri->tri[0] = (triangle) m->dummytri;
+ newotri->tri[1] = (triangle) m->dummytri;
+ newotri->tri[2] = (triangle) m->dummytri;
+ /* Three NULL vertices. */
+ newotri->tri[3] = (triangle) NULL;
+ newotri->tri[4] = (triangle) NULL;
+ newotri->tri[5] = (triangle) NULL;
+ if (b->usesegments) {
+ /* Initialize the three adjoining subsegments to be the omnipresent */
+ /* subsegment. */
+ newotri->tri[6] = (triangle) m->dummysub;
+ newotri->tri[7] = (triangle) m->dummysub;
+ newotri->tri[8] = (triangle) m->dummysub;
+ }
+ for (i = 0; i < m->eextras; i++) {
+ setelemattribute(*newotri, i, 0.0);
+ }
+ if (b->vararea) {
+ setareabound(*newotri, -1.0);
+ }
+
+ newotri->orient = 0;
+}
+
+/*****************************************************************************/
+/* */
+/* makesubseg() Create a new subsegment with orientation zero. */
+/* */
+/*****************************************************************************/
+
+void makesubseg(struct mesh *m, struct osub *newsubseg) {
+ newsubseg->ss = (subseg *) poolalloc(&m->subsegs);
+ /* Initialize the two adjoining subsegments to be the omnipresent */
+ /* subsegment. */
+ newsubseg->ss[0] = (subseg) m->dummysub;
+ newsubseg->ss[1] = (subseg) m->dummysub;
+ /* Four NULL vertices. */
+ newsubseg->ss[2] = (subseg) NULL;
+ newsubseg->ss[3] = (subseg) NULL;
+ newsubseg->ss[4] = (subseg) NULL;
+ newsubseg->ss[5] = (subseg) NULL;
+ /* Initialize the two adjoining triangles to be "outer space." */
+ newsubseg->ss[6] = (subseg) m->dummytri;
+ newsubseg->ss[7] = (subseg) m->dummytri;
+ /* Set the boundary marker to zero. */
+ setmark(*newsubseg, 0);
+
+ newsubseg->ssorient = 0;
+}
+
+/** **/
+/** **/
+/********* Constructors end here *********/
+
+/********* Geometric primitives begin here *********/
+/** **/
+/** **/
+
+/* The adaptive exact arithmetic geometric predicates implemented herein are */
+/* described in detail in my paper, "Adaptive Precision Floating-Point */
+/* Arithmetic and Fast Robust Geometric Predicates." See the header for a */
+/* full citation. */
+
+/* Which of the following two methods of finding the absolute values is */
+/* fastest is compiler-dependent. A few compilers can inline and optimize */
+/* the fabs() call; but most will incur the overhead of a function call, */
+/* which is disastrously slow. A faster way on IEEE machines might be to */
+/* mask the appropriate bit, but that's difficult to do in C without */
+/* forcing the value to be stored to memory (rather than be kept in the */
+/* register to which the optimizer assigned it). */
+
+#define Absolute(a) ((a) >= 0.0 ? (a) : -(a))
+/* #define Absolute(a) fabs(a) */
+
+/* Many of the operations are broken up into two pieces, a main part that */
+/* performs an approximate operation, and a "tail" that computes the */
+/* roundoff error of that operation. */
+/* */
+/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */
+/* Split(), and Two_Product() are all implemented as described in the */
+/* reference. Each of these macros requires certain variables to be */
+/* defined in the calling routine. The variables `bvirt', `c', `abig', */
+/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `' because */
+/* they store the result of an operation that may incur roundoff error. */
+/* The input parameter `x' (or the highest numbered `x_' parameter) must */
+/* also be declared `'. */
+
+#define Fast_Two_Sum_Tail(a, b, x, y) \
+ bvirt = x - a; \
+ y = b - bvirt
+
+#define Fast_Two_Sum(a, b, x, y) \
+ x = (REAL) (a + b); \
+ Fast_Two_Sum_Tail(a, b, x, y)
+
+#define Two_Sum_Tail(a, b, x, y) \
+ bvirt = (REAL) (x - a); \
+ avirt = x - bvirt; \
+ bround = b - bvirt; \
+ around = a - avirt; \
+ y = around + bround
+
+#define Two_Sum(a, b, x, y) \
+ x = (REAL) (a + b); \
+ Two_Sum_Tail(a, b, x, y)
+
+#define Two_Diff_Tail(a, b, x, y) \
+ bvirt = (REAL) (a - x); \
+ avirt = x + bvirt; \
+ bround = bvirt - b; \
+ around = a - avirt; \
+ y = around + bround
+
+#define Two_Diff(a, b, x, y) \
+ x = (REAL) (a - b); \
+ Two_Diff_Tail(a, b, x, y)
+
+#define Split(a, ahi, alo) \
+ c = (REAL) (splitter * a); \
+ abig = (REAL) (c - a); \
+ ahi = c - abig; \
+ alo = a - ahi
+
+#define Two_Product_Tail(a, b, x, y) \
+ Split(a, ahi, alo); \
+ Split(b, bhi, blo); \
+ err1 = x - (ahi * bhi); \
+ err2 = err1 - (alo * bhi); \
+ err3 = err2 - (ahi * blo); \
+ y = (alo * blo) - err3
+
+#define Two_Product(a, b, x, y) \
+ x = (REAL) (a * b); \
+ Two_Product_Tail(a, b, x, y)
+
+/* Two_Product_Presplit() is Two_Product() where one of the inputs has */
+/* already been split. Avoids redundant splitting. */
+
+#define Two_Product_Presplit(a, b, bhi, blo, x, y) \
+ x = (REAL) (a * b); \
+ Split(a, ahi, alo); \
+ err1 = x - (ahi * bhi); \
+ err2 = err1 - (alo * bhi); \
+ err3 = err2 - (ahi * blo); \
+ y = (alo * blo) - err3
+
+/* Square() can be done more quickly than Two_Product(). */
+
+#define Square_Tail(a, x, y) \
+ Split(a, ahi, alo); \
+ err1 = x - (ahi * ahi); \
+ err3 = err1 - ((ahi + ahi) * alo); \
+ y = (alo * alo) - err3
+
+#define Square(a, x, y) \
+ x = (REAL) (a * a); \
+ Square_Tail(a, x, y)
+
+/* Macros for summing expansions of various fixed lengths. These are all */
+/* unrolled versions of Expansion_Sum(). */
+
+#define Two_One_Sum(a1, a0, b, x2, x1, x0) \
+ Two_Sum(a0, b , _i, x0); \
+ Two_Sum(a1, _i, x2, x1)
+
+#define Two_One_Diff(a1, a0, b, x2, x1, x0) \
+ Two_Diff(a0, b , _i, x0); \
+ Two_Sum( a1, _i, x2, x1)
+
+#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \
+ Two_One_Sum(a1, a0, b0, _j, _0, x0); \
+ Two_One_Sum(_j, _0, b1, x3, x2, x1)
+
+#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \
+ Two_One_Diff(a1, a0, b0, _j, _0, x0); \
+ Two_One_Diff(_j, _0, b1, x3, x2, x1)
+
+/* Macro for multiplying a two-component expansion by a single component. */
+
+#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \
+ Split(b, bhi, blo); \
+ Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \
+ Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \
+ Two_Sum(_i, _0, _k, x1); \
+ Fast_Two_Sum(_j, _k, x3, x2)
+
+/*****************************************************************************/
+/* */
+/* exactinit() Initialize the variables used for exact arithmetic. */
+/* */
+/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */
+/* floating-point arithmetic. `epsilon' bounds the relative roundoff */
+/* error. It is used for floating-point error analysis. */
+/* */
+/* `splitter' is used to split floating-point numbers into two half- */
+/* length significands for exact multiplication. */
+/* */
+/* I imagine that a highly optimizing compiler might be too smart for its */
+/* own good, and somehow cause this routine to fail, if it pretends that */
+/* floating-point arithmetic is too much like real arithmetic. */
+/* */
+/* Don't change this routine unless you fully understand it. */
+/* */
+/*****************************************************************************/
+
+void exactinit() {
+ REAL half;
+ REAL check, lastcheck;
+ int every_other;
+#ifdef LINUX
+ int cword;
+#endif /* LINUX */
+
+#ifdef CPU86
+#ifdef SINGLE
+ _control87(_PC_24, _MCW_PC); /* Set FPU control word for single precision. */
+#else /* not SINGLE */
+ _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */
+#endif /* not SINGLE */
+#endif /* CPU86 */
+#ifdef LINUX
+#ifdef SINGLE
+ /* cword = 4223; */
+ cword = 4210; /* set FPU control word for single precision */
+#else /* not SINGLE */
+ /* cword = 4735; */
+ cword = 4722; /* set FPU control word for double precision */
+#endif /* not SINGLE */
+ _FPU_SETCW(cword);
+#endif /* LINUX */
+
+ every_other = 1;
+ half = 0.5;
+ epsilon = 1.0;
+ splitter = 1.0;
+ check = 1.0;
+ /* Repeatedly divide `epsilon' by two until it is too small to add to */
+ /* one without causing roundoff. (Also check if the sum is equal to */
+ /* the previous sum, for machines that round up instead of using exact */
+ /* rounding. Not that these routines will work on such machines.) */
+ do {
+ lastcheck = check;
+ epsilon *= half;
+ if (every_other) {
+ splitter *= 2.0;
+ }
+ every_other = !every_other;
+ check = 1.0 + epsilon;
+ } while ((check != 1.0) && (check != lastcheck));
+ splitter += 1.0;
+ /* Error bounds for orientation and incircle tests. */
+ resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
+ ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon;
+ ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon;
+ ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
+ iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
+ iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
+ iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon;
+ o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
+ o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
+ o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
+}
+
+/*****************************************************************************/
+/* */
+/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */
+/* components from the output expansion. */
+/* */
+/* Sets h = e + f. See my Robust Predicates paper for details. */
+/* */
+/* If round-to-even is used (as with IEEE 754), maintains the strongly */
+/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */
+/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */
+/* properties. */
+/* */
+/*****************************************************************************/
+
+int fast_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h) {
+ REAL Q;
+ REAL Qnew;
+ REAL hh;
+ REAL bvirt;
+ REAL avirt, bround, around;
+ int eindex, findex, hindex;
+ REAL enow, fnow;
+
+ enow = e[0];
+ fnow = f[0];
+ eindex = findex = 0;
+ if ((fnow > enow) == (fnow > -enow)) {
+ Q = enow;
+ enow = e[++eindex];
+ }
+ else {
+ Q = fnow;
+ fnow = f[++findex];
+ }
+ hindex = 0;
+ if ((eindex < elen) && (findex < flen)) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ Fast_Two_Sum(enow, Q, Qnew, hh);
+ enow = e[++eindex];
+ }
+ else {
+ Fast_Two_Sum(fnow, Q, Qnew, hh);
+ fnow = f[++findex];
+ }
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ while ((eindex < elen) && (findex < flen)) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ Two_Sum(Q, enow, Qnew, hh);
+ enow = e[++eindex];
+ }
+ else {
+ Two_Sum(Q, fnow, Qnew, hh);
+ fnow = f[++findex];
+ }
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ }
+ while (eindex < elen) {
+ Two_Sum(Q, enow, Qnew, hh);
+ enow = e[++eindex];
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ while (findex < flen) {
+ Two_Sum(Q, fnow, Qnew, hh);
+ fnow = f[++findex];
+ Q = Qnew;
+ if (hh != 0.0) {
+ h[hindex++] = hh;
+ }
+ }
+ if ((Q != 0.0) || (hindex == 0)) {
+ h[hindex++] = Q;
+ }
+ return hindex;
+}
+
+/*****************************************************************************/
+/* */
+/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */
+/* eliminating zero components from the */
+/* output expansion. */
+/* */
+/* Sets h = be. See my Robust Predicates paper for details. */
+/* */
+/* Maintains the nonoverlapping property. If round-to-even is used (as */
+/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */
+/* properties as well. (That is, if e has one of these properties, so */
+/* will h.) */
+/* */
+/*****************************************************************************/
+
+int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) {
+ REAL Q, sum;
+ REAL hh;
+ REAL product1;
+ REAL product0;
+ int eindex, hindex;
+ REAL enow;
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+
+ Split(b, bhi, blo);
+ Two_Product_Presplit(e[0], b, bhi, blo, Q, hh);
+ hindex = 0;
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ for (eindex = 1; eindex < elen; eindex++) {
+ enow = e[eindex];
+ Two_Product_Presplit(enow, b, bhi, blo, product1, product0);
+ Two_Sum(Q, product0, sum, hh);
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ Fast_Two_Sum(product1, sum, Q, hh);
+ if (hh != 0) {
+ h[hindex++] = hh;
+ }
+ }
+ if ((Q != 0.0) || (hindex == 0)) {
+ h[hindex++] = Q;
+ }
+ return hindex;
+}
+
+/*****************************************************************************/
+/* */
+/* estimate() Produce a one-word estimate of an expansion's value. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL estimate(int elen, REAL *e) {
+ REAL Q;
+ int eindex;
+
+ Q = e[0];
+ for (eindex = 1; eindex < elen; eindex++) {
+ Q += e[eindex];
+ }
+ return Q;
+}
+
+/*****************************************************************************/
+/* */
+/* counterclockwise() Return a positive value if the points pa, pb, and */
+/* pc occur in counterclockwise order; a negative */
+/* value if they occur in clockwise order; and zero */
+/* if they are collinear. The result is also a rough */
+/* approximation of twice the signed area of the */
+/* triangle defined by the three points. */
+/* */
+/* Uses exact arithmetic if necessary to ensure a correct answer. The */
+/* result returned is the determinant of a matrix. This determinant is */
+/* computed adaptively, in the sense that exact arithmetic is used only to */
+/* the degree it is needed to ensure that the returned value has the */
+/* correct sign. Hence, this function is usually quite fast, but will run */
+/* more slowly when the input points are collinear or nearly so. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL counterclockwiseadapt(vertex pa, vertex pb, vertex pc, REAL detsum) {
+ REAL acx, acy, bcx, bcy;
+ REAL acxtail, acytail, bcxtail, bcytail;
+ REAL detleft, detright;
+ REAL detlefttail, detrighttail;
+ REAL det, errbound;
+ REAL B[4], C1[8], C2[12], D[16];
+ REAL B3;
+ int C1length, C2length, Dlength;
+ REAL u[4];
+ REAL u3;
+ REAL s1, t1;
+ REAL s0, t0;
+
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+ REAL _i, _j;
+ REAL _0;
+
+ acx = (REAL) (pa[0] - pc[0]);
+ bcx = (REAL) (pb[0] - pc[0]);
+ acy = (REAL) (pa[1] - pc[1]);
+ bcy = (REAL) (pb[1] - pc[1]);
+
+ Two_Product(acx, bcy, detleft, detlefttail);
+ Two_Product(acy, bcx, detright, detrighttail);
+
+ Two_Two_Diff(detleft, detlefttail, detright, detrighttail, B3, B[2], B[1], B[0]);
+ B[3] = B3;
+
+ det = estimate(4, B);
+ errbound = ccwerrboundB * detsum;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pc[0], acx, acxtail);
+ Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail);
+ Two_Diff_Tail(pa[1], pc[1], acy, acytail);
+ Two_Diff_Tail(pb[1], pc[1], bcy, bcytail);
+
+ if ((acxtail == 0.0) && (acytail == 0.0) && (bcxtail == 0.0) && (bcytail == 0.0)) {
+ return det;
+ }
+
+ errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det);
+ det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Product(acxtail, bcy, s1, s0);
+ Two_Product(acytail, bcx, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1);
+
+ Two_Product(acx, bcytail, s1, s0);
+ Two_Product(acy, bcxtail, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2);
+
+ Two_Product(acxtail, bcytail, s1, s0);
+ Two_Product(acytail, bcxtail, t1, t0);
+ Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D);
+
+ return (D[Dlength - 1]);
+}
+
+REAL counterclockwise(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc) {
+ REAL detleft, detright, det;
+ REAL detsum, errbound;
+
+ m->counterclockcount++;
+
+ detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]);
+ detright = (pa[1] - pc[1]) * (pb[0] - pc[0]);
+ det = detleft - detright;
+
+ if (b->noexact) {
+ return det;
+ }
+
+ if (detleft > 0.0) {
+ if (detright <= 0.0) {
+ return det;
+ }
+ else {
+ detsum = detleft + detright;
+ }
+ }
+ else if (detleft < 0.0) {
+ if (detright >= 0.0) {
+ return det;
+ }
+ else {
+ detsum = -detleft - detright;
+ }
+ }
+ else {
+ return det;
+ }
+
+ errbound = ccwerrboundA * detsum;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ return counterclockwiseadapt(pa, pb, pc, detsum);
+}
+
+/*****************************************************************************/
+/* */
+/* incircle() Return a positive value if the point pd lies inside the */
+/* circle passing through pa, pb, and pc; a negative value if */
+/* it lies outside; and zero if the four points are cocircular.*/
+/* The points pa, pb, and pc must be in counterclockwise */
+/* order, or the sign of the result will be reversed. */
+/* */
+/* Uses exact arithmetic if necessary to ensure a correct answer. The */
+/* result returned is the determinant of a matrix. This determinant is */
+/* computed adaptively, in the sense that exact arithmetic is used only to */
+/* the degree it is needed to ensure that the returned value has the */
+/* correct sign. Hence, this function is usually quite fast, but will run */
+/* more slowly when the input points are cocircular or nearly so. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL incircleadapt(vertex pa, vertex pb, vertex pc, vertex pd, REAL permanent) {
+ REAL adx, bdx, cdx, ady, bdy, cdy;
+ REAL det, errbound;
+
+ REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+ REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+ REAL bc[4], ca[4], ab[4];
+ REAL bc3, ca3, ab3;
+ REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32];
+ int axbclen, axxbclen, aybclen, ayybclen, alen;
+ REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32];
+ int bxcalen, bxxcalen, bycalen, byycalen, blen;
+ REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32];
+ int cxablen, cxxablen, cyablen, cyyablen, clen;
+ REAL abdet[64];
+ int ablen;
+ REAL fin1[1152], fin2[1152];
+ REAL *finnow, *finother, *finswap;
+ int finlength;
+
+ REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail;
+ REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1;
+ REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0;
+ REAL aa[4], bb[4], cc[4];
+ REAL aa3, bb3, cc3;
+ REAL ti1, tj1;
+ REAL ti0, tj0;
+ REAL u[4], v[4];
+ REAL u3, v3;
+ REAL temp8[8], temp16a[16], temp16b[16], temp16c[16];
+ REAL temp32a[32], temp32b[32], temp48[48], temp64[64];
+ int temp8len, temp16alen, temp16blen, temp16clen;
+ int temp32alen, temp32blen, temp48len, temp64len;
+ REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8];
+ int axtbblen, axtcclen, aytbblen, aytcclen;
+ REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8];
+ int bxtaalen, bxtcclen, bytaalen, bytcclen;
+ REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8];
+ int cxtaalen, cxtbblen, cytaalen, cytbblen;
+ REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8];
+ int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen;
+ REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16];
+ int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen;
+ REAL axtbctt[8], aytbctt[8], bxtcatt[8];
+ REAL bytcatt[8], cxtabtt[8], cytabtt[8];
+ int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen;
+ REAL abt[8], bct[8], cat[8];
+ int abtlen, bctlen, catlen;
+ REAL abtt[4], bctt[4], catt[4];
+ int abttlen, bcttlen, cattlen;
+ REAL abtt3, bctt3, catt3;
+ REAL negate;
+
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+ REAL _i, _j;
+ REAL _0;
+
+ adx = (REAL) (pa[0] - pd[0]);
+ bdx = (REAL) (pb[0] - pd[0]);
+ cdx = (REAL) (pc[0] - pd[0]);
+ ady = (REAL) (pa[1] - pd[1]);
+ bdy = (REAL) (pb[1] - pd[1]);
+ cdy = (REAL) (pc[1] - pd[1]);
+
+ Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
+ Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
+ Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
+ bc[3] = bc3;
+ axbclen = scale_expansion_zeroelim(4, bc, adx, axbc);
+ axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc);
+ aybclen = scale_expansion_zeroelim(4, bc, ady, aybc);
+ ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc);
+ alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet);
+
+ Two_Product(cdx, ady, cdxady1, cdxady0);
+ Two_Product(adx, cdy, adxcdy1, adxcdy0);
+ Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
+ ca[3] = ca3;
+ bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca);
+ bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca);
+ bycalen = scale_expansion_zeroelim(4, ca, bdy, byca);
+ byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca);
+ blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet);
+
+ Two_Product(adx, bdy, adxbdy1, adxbdy0);
+ Two_Product(bdx, ady, bdxady1, bdxady0);
+ Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
+ ab[3] = ab3;
+ cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab);
+ cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab);
+ cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab);
+ cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab);
+ clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet);
+
+ ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+ finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
+
+ det = estimate(finlength, fin1);
+ errbound = iccerrboundB * permanent;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
+ Two_Diff_Tail(pa[1], pd[1], ady, adytail);
+ Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
+ Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
+ Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
+ Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
+ if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0)
+ && (bdytail == 0.0) && (cdytail == 0.0)) {
+ return det;
+ }
+
+ errbound = iccerrboundC * permanent + resulterrbound * Absolute(det);
+ det += ((adx * adx + ady * ady)
+ * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail))
+ + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx))
+ + ((bdx * bdx + bdy * bdy)
+ * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail))
+ + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx))
+ + ((cdx * cdx + cdy * cdy)
+ * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail))
+ + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx));
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ finnow = fin1;
+ finother = fin2;
+
+ if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) {
+ Square(adx, adxadx1, adxadx0);
+ Square(ady, adyady1, adyady0);
+ Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]);
+ aa[3] = aa3;
+ }
+ if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) {
+ Square(bdx, bdxbdx1, bdxbdx0);
+ Square(bdy, bdybdy1, bdybdy0);
+ Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]);
+ bb[3] = bb3;
+ }
+ if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) {
+ Square(cdx, cdxcdx1, cdxcdx0);
+ Square(cdy, cdycdy1, cdycdy0);
+ Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]);
+ cc[3] = cc3;
+ }
+
+ if (adxtail != 0.0) {
+ axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc);
+ temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, temp16a);
+
+ axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc);
+ temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b);
+
+ axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb);
+ temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc);
+ temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, temp16a);
+
+ aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb);
+ temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b);
+
+ aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc);
+ temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdxtail != 0.0) {
+ bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca);
+ temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, temp16a);
+
+ bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa);
+ temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b);
+
+ bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc);
+ temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca);
+ temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, temp16a);
+
+ bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc);
+ temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b);
+
+ bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa);
+ temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdxtail != 0.0) {
+ cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab);
+ temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, temp16a);
+
+ cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb);
+ temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b);
+
+ cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa);
+ temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab);
+ temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, temp16a);
+
+ cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa);
+ temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b);
+
+ cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb);
+ temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c);
+
+ temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ if ((adxtail != 0.0) || (adytail != 0.0)) {
+ if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) {
+ Two_Product(bdxtail, cdy, ti1, ti0);
+ Two_Product(bdx, cdytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -bdy;
+ Two_Product(cdxtail, negate, ti1, ti0);
+ negate = -bdytail;
+ Two_Product(cdx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct);
+
+ Two_Product(bdxtail, cdytail, ti1, ti0);
+ Two_Product(cdxtail, bdytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]);
+ bctt[3] = bctt3;
+ bcttlen = 4;
+ }
+ else {
+ bct[0] = 0.0;
+ bctlen = 1;
+ bctt[0] = 0.0;
+ bcttlen = 1;
+ }
+
+ if (adxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a);
+ axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct);
+ temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (bdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, temp32a);
+ axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt);
+ temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, temp16a);
+ temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a);
+ aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct);
+ temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, temp32a);
+ aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt);
+ temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, temp16a);
+ temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if ((bdxtail != 0.0) || (bdytail != 0.0)) {
+ if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) {
+ Two_Product(cdxtail, ady, ti1, ti0);
+ Two_Product(cdx, adytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -cdy;
+ Two_Product(adxtail, negate, ti1, ti0);
+ negate = -cdytail;
+ Two_Product(adx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat);
+
+ Two_Product(cdxtail, adytail, ti1, ti0);
+ Two_Product(adxtail, cdytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]);
+ catt[3] = catt3;
+ cattlen = 4;
+ }
+ else {
+ cat[0] = 0.0;
+ catlen = 1;
+ catt[0] = 0.0;
+ cattlen = 1;
+ }
+
+ if (bdxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a);
+ bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat);
+ temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (cdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (adytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, temp32a);
+ bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt);
+ temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, temp16a);
+ temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a);
+ bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat);
+ temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, temp32a);
+ bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt);
+ temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, temp16a);
+ temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if ((cdxtail != 0.0) || (cdytail != 0.0)) {
+ if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) {
+ Two_Product(adxtail, bdy, ti1, ti0);
+ Two_Product(adx, bdytail, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ negate = -ady;
+ Two_Product(bdxtail, negate, ti1, ti0);
+ negate = -adytail;
+ Two_Product(bdx, negate, tj1, tj0);
+ Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]);
+ v[3] = v3;
+ abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt);
+
+ Two_Product(adxtail, bdytail, ti1, ti0);
+ Two_Product(bdxtail, adytail, tj1, tj0);
+ Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]);
+ abtt[3] = abtt3;
+ abttlen = 4;
+ }
+ else {
+ abt[0] = 0.0;
+ abtlen = 1;
+ abtt[0] = 0.0;
+ abttlen = 1;
+ }
+
+ if (cdxtail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a);
+ cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt);
+ temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (adytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdytail != 0.0) {
+ temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8);
+ temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a,
+ finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, temp32a);
+ cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt);
+ temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, temp16a);
+ temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdytail != 0.0) {
+ temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a);
+ cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt);
+ temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, temp32a);
+ temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, temp32a);
+ cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt);
+ temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, temp16a);
+ temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, temp16b);
+ temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b,
+ temp32b);
+ temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+
+ return finnow[finlength - 1];
+}
+
+REAL incircle(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc, vertex pd) {
+ REAL adx, bdx, cdx, ady, bdy, cdy;
+ REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+ REAL alift, blift, clift;
+ REAL det;
+ REAL permanent, errbound;
+
+ m->incirclecount++;
+
+ adx = pa[0] - pd[0];
+ bdx = pb[0] - pd[0];
+ cdx = pc[0] - pd[0];
+ ady = pa[1] - pd[1];
+ bdy = pb[1] - pd[1];
+ cdy = pc[1] - pd[1];
+
+ bdxcdy = bdx * cdy;
+ cdxbdy = cdx * bdy;
+ alift = adx * adx + ady * ady;
+
+ cdxady = cdx * ady;
+ adxcdy = adx * cdy;
+ blift = bdx * bdx + bdy * bdy;
+
+ adxbdy = adx * bdy;
+ bdxady = bdx * ady;
+ clift = cdx * cdx + cdy * cdy;
+
+ det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady);
+
+ if (b->noexact) {
+ return det;
+ }
+
+ permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift
+ + (Absolute(cdxady) + Absolute(adxcdy)) * blift
+ + (Absolute(adxbdy) + Absolute(bdxady)) * clift;
+ errbound = iccerrboundA * permanent;
+ if ((det > errbound) || (-det > errbound)) {
+ return det;
+ }
+
+ return incircleadapt(pa, pb, pc, pd, permanent);
+}
+
+/*****************************************************************************/
+/* */
+/* orient3d() Return a positive value if the point pd lies below the */
+/* plane passing through pa, pb, and pc; "below" is defined so */
+/* that pa, pb, and pc appear in counterclockwise order when */
+/* viewed from above the plane. Returns a negative value if */
+/* pd lies above the plane. Returns zero if the points are */
+/* coplanar. The result is also a rough approximation of six */
+/* times the signed volume of the tetrahedron defined by the */
+/* four points. */
+/* */
+/* Uses exact arithmetic if necessary to ensure a correct answer. The */
+/* result returned is the determinant of a matrix. This determinant is */
+/* computed adaptively, in the sense that exact arithmetic is used only to */
+/* the degree it is needed to ensure that the returned value has the */
+/* correct sign. Hence, this function is usually quite fast, but will run */
+/* more slowly when the input points are coplanar or nearly so. */
+/* */
+/* See my Robust Predicates paper for details. */
+/* */
+/*****************************************************************************/
+
+REAL orient3dadapt(vertex pa, vertex pb, vertex pc, vertex pd, REAL aheight, REAL bheight,
+ REAL cheight, REAL dheight, REAL permanent) {
+ REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight;
+ REAL det, errbound;
+
+ REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
+ REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0;
+ REAL bc[4], ca[4], ab[4];
+ REAL bc3, ca3, ab3;
+ REAL adet[8], bdet[8], cdet[8];
+ int alen, blen, clen;
+ REAL abdet[16];
+ int ablen;
+ REAL *finnow, *finother, *finswap;
+ REAL fin1[192], fin2[192];
+ int finlength;
+
+ REAL adxtail, bdxtail, cdxtail;
+ REAL adytail, bdytail, cdytail;
+ REAL adheighttail, bdheighttail, cdheighttail;
+ REAL at_blarge, at_clarge;
+ REAL bt_clarge, bt_alarge;
+ REAL ct_alarge, ct_blarge;
+ REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
+ int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen;
+ REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1;
+ REAL adxt_cdy1, adxt_bdy1, bdxt_ady1;
+ REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0;
+ REAL adxt_cdy0, adxt_bdy0, bdxt_ady0;
+ REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1;
+ REAL adyt_cdx1, adyt_bdx1, bdyt_adx1;
+ REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0;
+ REAL adyt_cdx0, adyt_bdx0, bdyt_adx0;
+ REAL bct[8], cat[8], abt[8];
+ int bctlen, catlen, abtlen;
+ REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1;
+ REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1;
+ REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0;
+ REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0;
+ REAL u[4], v[12], w[16];
+ REAL u3;
+ int vlength, wlength;
+ REAL negate;
+
+ REAL bvirt;
+ REAL avirt, bround, around;
+ REAL c;
+ REAL abig;
+ REAL ahi, alo, bhi, blo;
+ REAL err1, err2, err3;
+ REAL _i, _j, _k;
+ REAL _0;
+
+ adx = (REAL) (pa[0] - pd[0]);
+ bdx = (REAL) (pb[0] - pd[0]);
+ cdx = (REAL) (pc[0] - pd[0]);
+ ady = (REAL) (pa[1] - pd[1]);
+ bdy = (REAL) (pb[1] - pd[1]);
+ cdy = (REAL) (pc[1] - pd[1]);
+ adheight = (REAL) (aheight - dheight);
+ bdheight = (REAL) (bheight - dheight);
+ cdheight = (REAL) (cheight - dheight);
+
+ Two_Product(bdx, cdy, bdxcdy1, bdxcdy0);
+ Two_Product(cdx, bdy, cdxbdy1, cdxbdy0);
+ Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
+ bc[3] = bc3;
+ alen = scale_expansion_zeroelim(4, bc, adheight, adet);
+
+ Two_Product(cdx, ady, cdxady1, cdxady0);
+ Two_Product(adx, cdy, adxcdy1, adxcdy0);
+ Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
+ ca[3] = ca3;
+ blen = scale_expansion_zeroelim(4, ca, bdheight, bdet);
+
+ Two_Product(adx, bdy, adxbdy1, adxbdy0);
+ Two_Product(bdx, ady, bdxady1, bdxady0);
+ Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
+ ab[3] = ab3;
+ clen = scale_expansion_zeroelim(4, ab, cdheight, cdet);
+
+ ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet);
+ finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1);
+
+ det = estimate(finlength, fin1);
+ errbound = o3derrboundB * permanent;
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ Two_Diff_Tail(pa[0], pd[0], adx, adxtail);
+ Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail);
+ Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail);
+ Two_Diff_Tail(pa[1], pd[1], ady, adytail);
+ Two_Diff_Tail(pb[1], pd[1], bdy, bdytail);
+ Two_Diff_Tail(pc[1], pd[1], cdy, cdytail);
+ Two_Diff_Tail(aheight, dheight, adheight, adheighttail);
+ Two_Diff_Tail(bheight, dheight, bdheight, bdheighttail);
+ Two_Diff_Tail(cheight, dheight, cdheight, cdheighttail);
+
+ if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0)
+ && (bdytail == 0.0) && (cdytail == 0.0) && (adheighttail == 0.0) && (bdheighttail == 0.0)
+ && (cdheighttail == 0.0)) {
+ return det;
+ }
+
+ errbound = o3derrboundC * permanent + resulterrbound * Absolute(det);
+ det += (adheight * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail))
+ + adheighttail * (bdx * cdy - bdy * cdx))
+ + (bdheight * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail))
+ + bdheighttail * (cdx * ady - cdy * adx))
+ + (cdheight * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail))
+ + cdheighttail * (adx * bdy - ady * bdx));
+ if ((det >= errbound) || (-det >= errbound)) {
+ return det;
+ }
+
+ finnow = fin1;
+ finother = fin2;
+
+ if (adxtail == 0.0) {
+ if (adytail == 0.0) {
+ at_b[0] = 0.0;
+ at_blen = 1;
+ at_c[0] = 0.0;
+ at_clen = 1;
+ }
+ else {
+ negate = -adytail;
+ Two_Product(negate, bdx, at_blarge, at_b[0]);
+ at_b[1] = at_blarge;
+ at_blen = 2;
+ Two_Product(adytail, cdx, at_clarge, at_c[0]);
+ at_c[1] = at_clarge;
+ at_clen = 2;
+ }
+ }
+ else {
+ if (adytail == 0.0) {
+ Two_Product(adxtail, bdy, at_blarge, at_b[0]);
+ at_b[1] = at_blarge;
+ at_blen = 2;
+ negate = -adxtail;
+ Two_Product(negate, cdy, at_clarge, at_c[0]);
+ at_c[1] = at_clarge;
+ at_clen = 2;
+ }
+ else {
+ Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0);
+ Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0);
+ Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, at_blarge, at_b[2], at_b[1],
+ at_b[0]);
+ at_b[3] = at_blarge;
+ at_blen = 4;
+ Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0);
+ Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0);
+ Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, at_clarge, at_c[2], at_c[1],
+ at_c[0]);
+ at_c[3] = at_clarge;
+ at_clen = 4;
+ }
+ }
+ if (bdxtail == 0.0) {
+ if (bdytail == 0.0) {
+ bt_c[0] = 0.0;
+ bt_clen = 1;
+ bt_a[0] = 0.0;
+ bt_alen = 1;
+ }
+ else {
+ negate = -bdytail;
+ Two_Product(negate, cdx, bt_clarge, bt_c[0]);
+ bt_c[1] = bt_clarge;
+ bt_clen = 2;
+ Two_Product(bdytail, adx, bt_alarge, bt_a[0]);
+ bt_a[1] = bt_alarge;
+ bt_alen = 2;
+ }
+ }
+ else {
+ if (bdytail == 0.0) {
+ Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]);
+ bt_c[1] = bt_clarge;
+ bt_clen = 2;
+ negate = -bdxtail;
+ Two_Product(negate, ady, bt_alarge, bt_a[0]);
+ bt_a[1] = bt_alarge;
+ bt_alen = 2;
+ }
+ else {
+ Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0);
+ Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0);
+ Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, bt_clarge, bt_c[2], bt_c[1],
+ bt_c[0]);
+ bt_c[3] = bt_clarge;
+ bt_clen = 4;
+ Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0);
+ Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0);
+ Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, bt_alarge, bt_a[2], bt_a[1],
+ bt_a[0]);
+ bt_a[3] = bt_alarge;
+ bt_alen = 4;
+ }
+ }
+ if (cdxtail == 0.0) {
+ if (cdytail == 0.0) {
+ ct_a[0] = 0.0;
+ ct_alen = 1;
+ ct_b[0] = 0.0;
+ ct_blen = 1;
+ }
+ else {
+ negate = -cdytail;
+ Two_Product(negate, adx, ct_alarge, ct_a[0]);
+ ct_a[1] = ct_alarge;
+ ct_alen = 2;
+ Two_Product(cdytail, bdx, ct_blarge, ct_b[0]);
+ ct_b[1] = ct_blarge;
+ ct_blen = 2;
+ }
+ }
+ else {
+ if (cdytail == 0.0) {
+ Two_Product(cdxtail, ady, ct_alarge, ct_a[0]);
+ ct_a[1] = ct_alarge;
+ ct_alen = 2;
+ negate = -cdxtail;
+ Two_Product(negate, bdy, ct_blarge, ct_b[0]);
+ ct_b[1] = ct_blarge;
+ ct_blen = 2;
+ }
+ else {
+ Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0);
+ Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0);
+ Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, ct_alarge, ct_a[2], ct_a[1],
+ ct_a[0]);
+ ct_a[3] = ct_alarge;
+ ct_alen = 4;
+ Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0);
+ Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0);
+ Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, ct_blarge, ct_b[2], ct_b[1],
+ ct_b[0]);
+ ct_b[3] = ct_blarge;
+ ct_blen = 4;
+ }
+ }
+
+ bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct);
+ wlength = scale_expansion_zeroelim(bctlen, bct, adheight, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat);
+ wlength = scale_expansion_zeroelim(catlen, cat, bdheight, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt);
+ wlength = scale_expansion_zeroelim(abtlen, abt, cdheight, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+
+ if (adheighttail != 0.0) {
+ vlength = scale_expansion_zeroelim(4, bc, adheighttail, v);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdheighttail != 0.0) {
+ vlength = scale_expansion_zeroelim(4, ca, bdheighttail, v);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdheighttail != 0.0) {
+ vlength = scale_expansion_zeroelim(4, ab, cdheighttail, v);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ if (adxtail != 0.0) {
+ if (bdytail != 0.0) {
+ Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0);
+ Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (cdheighttail != 0.0) {
+ Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if (cdytail != 0.0) {
+ negate = -adxtail;
+ Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0);
+ Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (bdheighttail != 0.0) {
+ Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ }
+ if (bdxtail != 0.0) {
+ if (cdytail != 0.0) {
+ Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0);
+ Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (adheighttail != 0.0) {
+ Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if (adytail != 0.0) {
+ negate = -bdxtail;
+ Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0);
+ Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (cdheighttail != 0.0) {
+ Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ }
+ if (cdxtail != 0.0) {
+ if (adytail != 0.0) {
+ Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0);
+ Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (bdheighttail != 0.0) {
+ Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ if (bdytail != 0.0) {
+ negate = -cdxtail;
+ Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0);
+ Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adheight, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ if (adheighttail != 0.0) {
+ Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adheighttail, u3, u[2], u[1], u[0]);
+ u[3] = u3;
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ }
+ }
+
+ if (adheighttail != 0.0) {
+ wlength = scale_expansion_zeroelim(bctlen, bct, adheighttail, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (bdheighttail != 0.0) {
+ wlength = scale_expansion_zeroelim(catlen, cat, bdheighttail, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+ if (cdheighttail != 0.0) {
+ wlength = scale_expansion_zeroelim(abtlen, abt, cdheighttail, w);
+ finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, finother);
+ finswap = finnow;
+ finnow = finother;
+ finother = finswap;
+ }
+
+ return finnow[finlength - 1];
+}
+
+REAL orient3d(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc, vertex pd,
+ REAL aheight, REAL bheight, REAL cheight, REAL dheight) {
+ REAL adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight;
+ REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
+ REAL det;
+ REAL permanent, errbound;
+
+ m->orient3dcount++;
+
+ adx = pa[0] - pd[0];
+ bdx = pb[0] - pd[0];
+ cdx = pc[0] - pd[0];
+ ady = pa[1] - pd[1];
+ bdy = pb[1] - pd[1];
+ cdy = pc[1] - pd[1];
+ adheight = aheight - dheight;
+ bdheight = bheight - dheight;
+ cdheight = cheight - dheight;
+
+ bdxcdy = bdx * cdy;
+ cdxbdy = cdx * bdy;
+
+ cdxady = cdx * ady;
+ adxcdy = adx * cdy;
+
+ adxbdy = adx * bdy;
+ bdxady = bdx * ady;
+
+ det = adheight * (bdxcdy - cdxbdy) + bdheight * (cdxady - adxcdy) + cdheight * (adxbdy - bdxady);
+
+ if (b->noexact) {
+ return det;
+ }
+
+ permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adheight)
+ + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdheight)
+ + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdheight);
+ errbound = o3derrboundA * permanent;
+ if ((det > errbound) || (-det > errbound)) {
+ return det;
+ }
+
+ return orient3dadapt(pa, pb, pc, pd, aheight, bheight, cheight, dheight, permanent);
+}
+
+/*****************************************************************************/
+/* */
+/* nonregular() Return a positive value if the point pd is incompatible */
+/* with the circle or plane passing through pa, pb, and pc */
+/* (meaning that pd is inside the circle or below the */
+/* plane); a negative value if it is compatible; and zero if */
+/* the four points are cocircular/coplanar. The points pa, */
+/* pb, and pc must be in counterclockwise order, or the sign */
+/* of the result will be reversed. */
+/* */
+/* If the -w switch is used, the points are lifted onto the parabolic */
+/* lifting map, then they are dropped according to their weights, then the */
+/* 3D orientation test is applied. If the -W switch is used, the points' */
+/* heights are already provided, so the 3D orientation test is applied */
+/* directly. If neither switch is used, the incircle test is applied. */
+/* */
+/*****************************************************************************/
+
+REAL nonregular(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc, vertex pd) {
+ if (b->weighted == 0) {
+ return incircle(m, b, pa, pb, pc, pd);
+ }
+ else if (b->weighted == 1) {
+ return orient3d(m, b, pa, pb, pc, pd, pa[0] * pa[0] + pa[1] * pa[1] - pa[2],
+ pb[0] * pb[0] + pb[1] * pb[1] - pb[2], pc[0] * pc[0] + pc[1] * pc[1] - pc[2],
+ pd[0] * pd[0] + pd[1] * pd[1] - pd[2]);
+ }
+ else {
+ return orient3d(m, b, pa, pb, pc, pd, pa[2], pb[2], pc[2], pd[2]);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* findcircumcenter() Find the circumcenter of a triangle. */
+/* */
+/* The result is returned both in terms of x-y coordinates and xi-eta */
+/* (barycentric) coordinates. The xi-eta coordinate system is defined in */
+/* terms of the triangle: the origin of the triangle is the origin of the */
+/* coordinate system; the destination of the triangle is one unit along the */
+/* xi axis; and the apex of the triangle is one unit along the eta axis. */
+/* This procedure also returns the square of the length of the triangle's */
+/* shortest edge. */
+/* */
+/*****************************************************************************/
+
+void findcircumcenter(struct mesh *m, struct behavior *b, vertex torg, vertex tdest, vertex tapex,
+ vertex circumcenter, REAL *xi, REAL *eta, int offcenter) {
+ REAL xdo, ydo, xao, yao;
+ REAL dodist, aodist, dadist;
+ REAL denominator;
+ REAL dx, dy, dxoff, dyoff;
+
+ m->circumcentercount++;
+
+ /* Compute the circumcenter of the triangle. */
+ xdo = tdest[0] - torg[0];
+ ydo = tdest[1] - torg[1];
+ xao = tapex[0] - torg[0];
+ yao = tapex[1] - torg[1];
+ dodist = xdo * xdo + ydo * ydo;
+ aodist = xao * xao + yao * yao;
+ dadist = (tdest[0] - tapex[0]) * (tdest[0] - tapex[0])
+ + (tdest[1] - tapex[1]) * (tdest[1] - tapex[1]);
+ if (b->noexact) {
+ denominator = 0.5 / (xdo * yao - xao * ydo);
+ }
+ else {
+ /* Use the counterclockwise() routine to ensure a positive (and */
+ /* reasonably accurate) result, avoiding any possibility of */
+ /* division by zero. */
+ denominator = 0.5 / counterclockwise(m, b, tdest, tapex, torg);
+ /* Don't count the above as an orientation test. */
+ m->counterclockcount--;
+ }
+ dx = (yao * dodist - ydo * aodist) * denominator;
+ dy = (xdo * aodist - xao * dodist) * denominator;
+
+ /* Find the (squared) length of the triangle's shortest edge. This */
+ /* serves as a conservative estimate of the insertion radius of the */
+ /* circumcenter's parent. The estimate is used to ensure that */
+ /* the algorithm terminates even if very small angles appear in */
+ /* the input PSLG. */
+ if ((dodist < aodist) && (dodist < dadist)) {
+ if (offcenter && (b->offconstant > 0.0)) {
+ /* Find the position of the off-center, as described by Alper Ungor. */
+ dxoff = 0.5 * xdo - b->offconstant * ydo;
+ dyoff = 0.5 * ydo + b->offconstant * xdo;
+ /* If the off-center is closer to the origin than the */
+ /* circumcenter, use the off-center instead. */
+ if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) {
+ dx = dxoff;
+ dy = dyoff;
+ }
+ }
+ }
+ else if (aodist < dadist) {
+ if (offcenter && (b->offconstant > 0.0)) {
+ dxoff = 0.5 * xao + b->offconstant * yao;
+ dyoff = 0.5 * yao - b->offconstant * xao;
+ /* If the off-center is closer to the origin than the */
+ /* circumcenter, use the off-center instead. */
+ if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy) {
+ dx = dxoff;
+ dy = dyoff;
+ }
+ }
+ }
+ else {
+ if (offcenter && (b->offconstant > 0.0)) {
+ dxoff = 0.5 * (tapex[0] - tdest[0]) - b->offconstant * (tapex[1] - tdest[1]);
+ dyoff = 0.5 * (tapex[1] - tdest[1]) + b->offconstant * (tapex[0] - tdest[0]);
+ /* If the off-center is closer to the destination than the */
+ /* circumcenter, use the off-center instead. */
+ if (dxoff * dxoff + dyoff * dyoff < (dx - xdo) * (dx - xdo) + (dy - ydo) * (dy - ydo)) {
+ dx = xdo + dxoff;
+ dy = ydo + dyoff;
+ }
+ }
+ }
+
+ circumcenter[0] = torg[0] + dx;
+ circumcenter[1] = torg[1] + dy;
+
+ /* To interpolate vertex attributes for the new vertex inserted at */
+ /* the circumcenter, define a coordinate system with a xi-axis, */
+ /* directed from the triangle's origin to its destination, and */
+ /* an eta-axis, directed from its origin to its apex. */
+ /* Calculate the xi and eta coordinates of the circumcenter. */
+ *xi = (yao * dx - xao * dy) * (2.0 * denominator);
+ *eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
+}
+
+/** **/
+/** **/
+/********* Geometric primitives end here *********/
+
+/*****************************************************************************/
+/* */
+/* triangleinit() Initialize some variables. */
+/* */
+/*****************************************************************************/
+
+void triangleinit(struct mesh *m) {
+ poolzero(&m->vertices);
+ poolzero(&m->triangles);
+ poolzero(&m->subsegs);
+ poolzero(&m->viri);
+ poolzero(&m->badsubsegs);
+ poolzero(&m->badtriangles);
+ poolzero(&m->flipstackers);
+ poolzero(&m->splaynodes);
+
+ m->recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */
+ m->undeads = 0; /* No eliminated input vertices yet. */
+ m->samples = 1; /* Point location should take at least one sample. */
+ m->checksegments = 0; /* There are no segments in the triangulation yet. */
+ m->checkquality = 0; /* The quality triangulation stage has not begun. */
+ m->incirclecount = m->counterclockcount = m->orient3dcount = 0;
+ m->hyperbolacount = m->circletopcount = m->circumcentercount = 0;
+ randomseed = 1;
+
+ exactinit(); /* Initialize exact arithmetic constants. */
+}
+
+/*****************************************************************************/
+/* */
+/* randomnation() Generate a random number between 0 and `choices' - 1. */
+/* */
+/* This is a simple linear congruential random number generator. Hence, it */
+/* is a bad random number generator, but good enough for most randomized */
+/* geometric algorithms. */
+/* */
+/*****************************************************************************/
+
+unsigned long randomnation(unsigned int choices) {
+ randomseed = (randomseed * 1366l + 150889l) % 714025l;
+ return randomseed / (714025l / choices + 1);
+}
+
+/********* Point location routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* makevertexmap() Construct a mapping from vertices to triangles to */
+/* improve the speed of point location for segment */
+/* insertion. */
+/* */
+/* Traverses all the triangles, and provides each corner of each triangle */
+/* with a pointer to that triangle. Of course, pointers will be */
+/* overwritten by other pointers because (almost) each vertex is a corner */
+/* of several triangles, but in the end every vertex will point to some */
+/* triangle that contains it. */
+/* */
+/*****************************************************************************/
+
+void makevertexmap(struct mesh *m, struct behavior *b) {
+ struct otri triangleloop;
+ vertex triorg;
+
+ if (b->verbose) {
+ printf(" Constructing mapping from vertices to triangles.\n");
+ }
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ while (triangleloop.tri != (triangle *) NULL) {
+ /* Check all three vertices of the triangle. */
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ org(triangleloop, triorg);
+ setvertex2tri(triorg, encode(triangleloop));
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* preciselocate() Find a triangle or edge containing a given point. */
+/* */
+/* Begins its search from `searchtri'. It is important that `searchtri' */
+/* be a handle with the property that `searchpoint' is strictly to the left */
+/* of the edge denoted by `searchtri', or is collinear with that edge and */
+/* does not intersect that edge. (In particular, `searchpoint' should not */
+/* be the origin or destination of that edge.) */
+/* */
+/* These conditions are imposed because preciselocate() is normally used in */
+/* one of two situations: */
+/* */
+/* (1) To try to find the location to insert a new point. Normally, we */
+/* know an edge that the point is strictly to the left of. In the */
+/* incremental Delaunay algorithm, that edge is a bounding box edge. */
+/* In Ruppert's Delaunay refinement algorithm for quality meshing, */
+/* that edge is the shortest edge of the triangle whose circumcenter */
+/* is being inserted. */
+/* */
+/* (2) To try to find an existing point. In this case, any edge on the */
+/* convex hull is a good starting edge. You must screen out the */
+/* possibility that the vertex sought is an endpoint of the starting */
+/* edge before you call preciselocate(). */
+/* */
+/* On completion, `searchtri' is a triangle that contains `searchpoint'. */
+/* */
+/* This implementation differs from that given by Guibas and Stolfi. It */
+/* walks from triangle to triangle, crossing an edge only if `searchpoint' */
+/* is on the other side of the line containing that edge. After entering */
+/* a triangle, there are two edges by which one can leave that triangle. */
+/* If both edges are valid (`searchpoint' is on the other side of both */
+/* edges), one of the two is chosen by drawing a line perpendicular to */
+/* the entry edge (whose endpoints are `forg' and `fdest') passing through */
+/* `fapex'. Depending on which side of this perpendicular `searchpoint' */
+/* falls on, an exit edge is chosen. */
+/* */
+/* This implementation is empirically faster than the Guibas and Stolfi */
+/* point location routine (which I originally used), which tends to spiral */
+/* in toward its target. */
+/* */
+/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */
+/* is a handle whose origin is the existing vertex. */
+/* */
+/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */
+/* handle whose primary edge is the edge on which the point lies. */
+/* */
+/* Returns INTRIANGLE if the point lies strictly within a triangle. */
+/* `searchtri' is a handle on the triangle that contains the point. */
+/* */
+/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */
+/* handle whose primary edge the point is to the right of. This might */
+/* occur when the circumcenter of a triangle falls just slightly outside */
+/* the mesh due to floating-point roundoff error. It also occurs when */
+/* seeking a hole or region point that a foolish user has placed outside */
+/* the mesh. */
+/* */
+/* If `stopatsubsegment' is nonzero, the search will stop if it tries to */
+/* walk through a subsegment, and will return OUTSIDE. */
+/* */
+/* WARNING: This routine is designed for convex triangulations, and will */
+/* not generally work after the holes and concavities have been carved. */
+/* However, it can still be used to find the circumcenter of a triangle, as */
+/* long as the search is begun from the triangle in question. */
+/* */
+/*****************************************************************************/
+
+enum locateresult preciselocate(struct mesh *m, struct behavior *b, vertex searchpoint,
+ struct otri *searchtri, int stopatsubsegment) {
+ struct otri backtracktri;
+ struct osub checkedge;
+ vertex forg, fdest, fapex;
+ REAL orgorient, destorient;
+ int moveleft;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose > 2) {
+ printf(" Searching for point (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ }
+ /* Where are we? */
+ org(*searchtri, forg);
+ dest(*searchtri, fdest);
+ apex(*searchtri, fapex);
+ while (1) {
+ if (b->verbose > 2) {
+ printf(
+ " At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]);
+ }
+ /* Check whether the apex is the point we seek. */
+ if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) {
+ lprevself(*searchtri);
+ return ONVERTEX;
+ }
+ /* Does the point lie on the other side of the line defined by the */
+ /* triangle edge opposite the triangle's destination? */
+ destorient = counterclockwise(m, b, forg, fapex, searchpoint);
+ /* Does the point lie on the other side of the line defined by the */
+ /* triangle edge opposite the triangle's origin? */
+ orgorient = counterclockwise(m, b, fapex, fdest, searchpoint);
+ if (destorient > 0.0) {
+ if (orgorient > 0.0) {
+ /* Move left if the inner product of (fapex - searchpoint) and */
+ /* (fdest - forg) is positive. This is equivalent to drawing */
+ /* a line perpendicular to the line (forg, fdest) and passing */
+ /* through `fapex', and determining which side of this line */
+ /* `searchpoint' falls on. */
+ moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0])
+ + (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0;
+ }
+ else {
+ moveleft = 1;
+ }
+ }
+ else {
+ if (orgorient > 0.0) {
+ moveleft = 0;
+ }
+ else {
+ /* The point we seek must be on the boundary of or inside this */
+ /* triangle. */
+ if (destorient == 0.0) {
+ lprevself(*searchtri);
+ return ONEDGE;
+ }
+ if (orgorient == 0.0) {
+ lnextself(*searchtri);
+ return ONEDGE;
+ }
+ return INTRIANGLE;
+ }
+ }
+
+ /* Move to another triangle. Leave a trace `backtracktri' in case */
+ /* floating-point roundoff or some such bogey causes us to walk */
+ /* off a boundary of the triangulation. */
+ if (moveleft) {
+ lprev(*searchtri, backtracktri);
+ fdest = fapex;
+ }
+ else {
+ lnext(*searchtri, backtracktri);
+ forg = fapex;
+ }
+ sym(backtracktri, *searchtri);
+
+ if (m->checksegments && stopatsubsegment) {
+ /* Check for walking through a subsegment. */
+ tspivot(backtracktri, checkedge);
+ if (checkedge.ss != m->dummysub) {
+ /* Go back to the last triangle. */
+ otricopy(backtracktri, *searchtri);
+ return OUTSIDE;
+ }
+ }
+ /* Check for walking right out of the triangulation. */
+ if (searchtri->tri == m->dummytri) {
+ /* Go back to the last triangle. */
+ otricopy(backtracktri, *searchtri);
+ return OUTSIDE;
+ }
+
+ apex(*searchtri, fapex);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* locate() Find a triangle or edge containing a given point. */
+/* */
+/* Searching begins from one of: the input `searchtri', a recently */
+/* encountered triangle `recenttri', or from a triangle chosen from a */
+/* random sample. The choice is made by determining which triangle's */
+/* origin is closest to the point we are searching for. Normally, */
+/* `searchtri' should be a handle on the convex hull of the triangulation. */
+/* */
+/* Details on the random sampling method can be found in the Mucke, Saias, */
+/* and Zhu paper cited in the header of this code. */
+/* */
+/* On completion, `searchtri' is a triangle that contains `searchpoint'. */
+/* */
+/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */
+/* is a handle whose origin is the existing vertex. */
+/* */
+/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */
+/* handle whose primary edge is the edge on which the point lies. */
+/* */
+/* Returns INTRIANGLE if the point lies strictly within a triangle. */
+/* `searchtri' is a handle on the triangle that contains the point. */
+/* */
+/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */
+/* handle whose primary edge the point is to the right of. This might */
+/* occur when the circumcenter of a triangle falls just slightly outside */
+/* the mesh due to floating-point roundoff error. It also occurs when */
+/* seeking a hole or region point that a foolish user has placed outside */
+/* the mesh. */
+/* */
+/* WARNING: This routine is designed for convex triangulations, and will */
+/* not generally work after the holes and concavities have been carved. */
+/* */
+/*****************************************************************************/
+
+enum locateresult locate(struct mesh *m, struct behavior *b, vertex searchpoint,
+ struct otri *searchtri) {
+ VOID **sampleblock;
+ char *firsttri;
+ struct otri sampletri;
+ vertex torg, tdest;
+ unsigned long alignptr;
+ REAL searchdist, dist;
+ REAL ahead;
+ long samplesperblock, totalsamplesleft, samplesleft;
+ long population, totalpopulation;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (b->verbose > 2) {
+ printf(
+ " Randomly sampling for a triangle near point (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ }
+ /* Record the distance from the suggested starting triangle to the */
+ /* point we seek. */
+ org(*searchtri, torg);
+ searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+ + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+ if (b->verbose > 2) {
+ printf(" Boundary triangle has origin (%.12g, %.12g).\n", torg[0], torg[1]);
+ }
+
+ /* If a recently encountered triangle has been recorded and has not been */
+ /* deallocated, test it as a good starting point. */
+ if (m->recenttri.tri != (triangle *) NULL) {
+ if (!deadtri(m->recenttri.tri)) {
+ org(m->recenttri, torg);
+ if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+ otricopy(m->recenttri, *searchtri);
+ return ONVERTEX;
+ }
+ dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+ + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+ if (dist < searchdist) {
+ otricopy(m->recenttri, *searchtri);
+ searchdist = dist;
+ if (b->verbose > 2) {
+ printf(
+ " Choosing recent triangle with origin (%.12g, %.12g).\n", torg[0], torg[1]);
+ }
+ }
+ }
+ }
+
+ /* The number of random samples taken is proportional to the cube root of */
+ /* the number of triangles in the mesh. The next bit of code assumes */
+ /* that the number of triangles increases monotonically (or at least */
+ /* doesn't decrease enough to matter). */
+ while (SAMPLEFACTOR * m->samples * m->samples * m->samples < m->triangles.items) {
+ m->samples++;
+ }
+
+ /* We'll draw ceiling(samples * TRIPERBLOCK / maxitems) random samples */
+ /* from each block of triangles (except the first)--until we meet the */
+ /* sample quota. The ceiling means that blocks at the end might be */
+ /* neglected, but I don't care. */
+ samplesperblock = (m->samples * TRIPERBLOCK - 1) / m->triangles.maxitems + 1;
+ /* We'll draw ceiling(samples * itemsfirstblock / maxitems) random samples */
+ /* from the first block of triangles. */
+ samplesleft = (m->samples * m->triangles.itemsfirstblock - 1) / m->triangles.maxitems + 1;
+ totalsamplesleft = m->samples;
+ population = m->triangles.itemsfirstblock;
+ totalpopulation = m->triangles.maxitems;
+ sampleblock = m->triangles.firstblock;
+ sampletri.orient = 0;
+ while (totalsamplesleft > 0) {
+ /* If we're in the last block, `population' needs to be corrected. */
+ if (population > totalpopulation) {
+ population = totalpopulation;
+ }
+ /* Find a pointer to the first triangle in the block. */
+ alignptr = (unsigned long) (sampleblock + 1);
+ firsttri = (char *) (alignptr + (unsigned long) m->triangles.alignbytes
+ - (alignptr % (unsigned long) m->triangles.alignbytes));
+
+ /* Choose `samplesleft' randomly sampled triangles in this block. */
+ do {
+ sampletri.tri = (triangle *) (firsttri
+ + (randomnation((unsigned int) population) * m->triangles.itembytes));
+ if (!deadtri(sampletri.tri)) {
+ org(sampletri, torg);
+ dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0])
+ + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]);
+ if (dist < searchdist) {
+ otricopy(sampletri, *searchtri);
+ searchdist = dist;
+ if (b->verbose > 2) {
+ printf(" Choosing triangle with origin (%.12g, %.12g).\n", torg[0], torg[1]);
+ }
+ }
+ }
+
+ samplesleft--;
+ totalsamplesleft--;
+ } while ((samplesleft > 0) && (totalsamplesleft > 0));
+
+ if (totalsamplesleft > 0) {
+ sampleblock = (VOID **) *sampleblock;
+ samplesleft = samplesperblock;
+ totalpopulation -= population;
+ population = TRIPERBLOCK;
+ }
+ }
+
+ /* Where are we? */
+ org(*searchtri, torg);
+ dest(*searchtri, tdest);
+ /* Check the starting triangle's vertices. */
+ if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) {
+ return ONVERTEX;
+ }
+ if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) {
+ lnextself(*searchtri);
+ return ONVERTEX;
+ }
+ /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */
+ ahead = counterclockwise(m, b, torg, tdest, searchpoint);
+ if (ahead < 0.0) {
+ /* Turn around so that `searchpoint' is to the left of the */
+ /* edge specified by `searchtri'. */
+ symself(*searchtri);
+ }
+ else if (ahead == 0.0) {
+ /* Check if `searchpoint' is between `torg' and `tdest'. */
+ if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0]))
+ && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) {
+ return ONEDGE;
+ }
+ }
+ return preciselocate(m, b, searchpoint, searchtri, 0);
+}
+
+/** **/
+/** **/
+/********* Point location routines end here *********/
+
+/********* Mesh transformation routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* insertsubseg() Create a new subsegment and insert it between two */
+/* triangles. */
+/* */
+/* The new subsegment is inserted at the edge described by the handle */
+/* `tri'. Its vertices are properly initialized. The marker `subsegmark' */
+/* is applied to the subsegment and, if appropriate, its vertices. */
+/* */
+/*****************************************************************************/
+
+void insertsubseg(struct mesh *m, struct behavior *b, struct otri *tri, int subsegmark) {
+ struct otri oppotri;
+ struct osub newsubseg;
+ vertex triorg, tridest;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ org(*tri, triorg);
+ dest(*tri, tridest);
+ /* Mark vertices if possible. */
+ if (vertexmark(triorg) == 0) {
+ setvertexmark(triorg, subsegmark);
+ }
+ if (vertexmark(tridest) == 0) {
+ setvertexmark(tridest, subsegmark);
+ }
+ /* Check if there's already a subsegment here. */
+ tspivot(*tri, newsubseg);
+ if (newsubseg.ss == m->dummysub) {
+ /* Make new subsegment and initialize its vertices. */
+ makesubseg(m, &newsubseg);
+ setsorg(newsubseg, tridest);
+ setsdest(newsubseg, triorg);
+ setsegorg(newsubseg, tridest);
+ setsegdest(newsubseg, triorg);
+ /* Bond new subsegment to the two triangles it is sandwiched between. */
+ /* Note that the facing triangle `oppotri' might be equal to */
+ /* `dummytri' (outer space), but the new subsegment is bonded to it */
+ /* all the same. */
+ tsbond(*tri, newsubseg);
+ sym(*tri, oppotri);
+ ssymself(newsubseg);
+ tsbond(oppotri, newsubseg);
+ setmark(newsubseg, subsegmark);
+ if (b->verbose > 2) {
+ printf(" Inserting new ");
+ printsubseg(m, b, &newsubseg);
+ }
+ }
+ else {
+ if (mark(newsubseg) == 0) {
+ setmark(newsubseg, subsegmark);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* Terminology */
+/* */
+/* A "local transformation" replaces a small set of triangles with another */
+/* set of triangles. This may or may not involve inserting or deleting a */
+/* vertex. */
+/* */
+/* The term "casing" is used to describe the set of triangles that are */
+/* attached to the triangles being transformed, but are not transformed */
+/* themselves. Think of the casing as a fixed hollow structure inside */
+/* which all the action happens. A "casing" is only defined relative to */
+/* a single transformation; each occurrence of a transformation will */
+/* involve a different casing. */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* */
+/* flip() Transform two triangles to two different triangles by flipping */
+/* an edge counterclockwise within a quadrilateral. */
+/* */
+/* Imagine the original triangles, abc and bad, oriented so that the */
+/* shared edge ab lies in a horizontal plane, with the vertex b on the left */
+/* and the vertex a on the right. The vertex c lies below the edge, and */
+/* the vertex d lies above the edge. The `flipedge' handle holds the edge */
+/* ab of triangle abc, and is directed left, from vertex a to vertex b. */
+/* */
+/* The triangles abc and bad are deleted and replaced by the triangles cdb */
+/* and dca. The triangles that represent abc and bad are NOT deallocated; */
+/* they are reused for dca and cdb, respectively. Hence, any handles that */
+/* may have held the original triangles are still valid, although not */
+/* directed as they were before. */
+/* */
+/* Upon completion of this routine, the `flipedge' handle holds the edge */
+/* dc of triangle dca, and is directed down, from vertex d to vertex c. */
+/* (Hence, the two triangles have rotated counterclockwise.) */
+/* */
+/* WARNING: This transformation is geometrically valid only if the */
+/* quadrilateral adbc is convex. Furthermore, this transformation is */
+/* valid only if there is not a subsegment between the triangles abc and */
+/* bad. This routine does not check either of these preconditions, and */
+/* it is the responsibility of the calling routine to ensure that they are */
+/* met. If they are not, the streets shall be filled with wailing and */
+/* gnashing of teeth. */
+/* */
+/*****************************************************************************/
+
+void flip(struct mesh *m, struct behavior *b, struct otri *flipedge) {
+ struct otri botleft, botright;
+ struct otri topleft, topright;
+ struct otri top;
+ struct otri botlcasing, botrcasing;
+ struct otri toplcasing, toprcasing;
+ struct osub botlsubseg, botrsubseg;
+ struct osub toplsubseg, toprsubseg;
+ vertex leftvertex, rightvertex, botvertex;
+ vertex farvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ /* Identify the vertices of the quadrilateral. */
+ org(*flipedge, rightvertex);
+ dest(*flipedge, leftvertex);
+ apex(*flipedge, botvertex);
+ sym(*flipedge, top);
+#ifdef SELF_CHECK
+ if (top.tri == m->dummytri)
+ {
+ printf("Internal error in flip(): Attempt to flip on boundary.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ if (m->checksegments)
+ {
+ tspivot(*flipedge, toplsubseg);
+ if (toplsubseg.ss != m->dummysub)
+ {
+ printf("Internal error in flip(): Attempt to flip a segment.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ }
+#endif /* SELF_CHECK */
+ apex(top, farvertex);
+
+ /* Identify the casing of the quadrilateral. */
+ lprev(top, topleft);
+ sym(topleft, toplcasing);
+ lnext(top, topright);
+ sym(topright, toprcasing);
+ lnext(*flipedge, botleft);
+ sym(botleft, botlcasing);
+ lprev(*flipedge, botright);
+ sym(botright, botrcasing);
+ /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+ bond(topleft, botlcasing);
+ bond(botleft, botrcasing);
+ bond(botright, toprcasing);
+ bond(topright, toplcasing);
+
+ if (m->checksegments) {
+ /* Check for subsegments and rebond them to the quadrilateral. */
+ tspivot(topleft, toplsubseg);
+ tspivot(botleft, botlsubseg);
+ tspivot(botright, botrsubseg);
+ tspivot(topright, toprsubseg);
+ if (toplsubseg.ss == m->dummysub) {
+ tsdissolve(topright);
+ }
+ else {
+ tsbond(topright, toplsubseg);
+ }
+ if (botlsubseg.ss == m->dummysub) {
+ tsdissolve(topleft);
+ }
+ else {
+ tsbond(topleft, botlsubseg);
+ }
+ if (botrsubseg.ss == m->dummysub) {
+ tsdissolve(botleft);
+ }
+ else {
+ tsbond(botleft, botrsubseg);
+ }
+ if (toprsubseg.ss == m->dummysub) {
+ tsdissolve(botright);
+ }
+ else {
+ tsbond(botright, toprsubseg);
+ }
+ }
+
+ /* New vertex assignments for the rotated quadrilateral. */
+ setorg(*flipedge, farvertex);
+ setdest(*flipedge, botvertex);
+ setapex(*flipedge, rightvertex);
+ setorg(top, botvertex);
+ setdest(top, farvertex);
+ setapex(top, leftvertex);
+ if (b->verbose > 2) {
+ printf(" Edge flip results in left ");
+ printtriangle(m, b, &top);
+ printf(" and right ");
+ printtriangle(m, b, flipedge);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* unflip() Transform two triangles to two different triangles by */
+/* flipping an edge clockwise within a quadrilateral. Reverses */
+/* the flip() operation so that the data structures representing */
+/* the triangles are back where they were before the flip(). */
+/* */
+/* Imagine the original triangles, abc and bad, oriented so that the */
+/* shared edge ab lies in a horizontal plane, with the vertex b on the left */
+/* and the vertex a on the right. The vertex c lies below the edge, and */
+/* the vertex d lies above the edge. The `flipedge' handle holds the edge */
+/* ab of triangle abc, and is directed left, from vertex a to vertex b. */
+/* */
+/* The triangles abc and bad are deleted and replaced by the triangles cdb */
+/* and dca. The triangles that represent abc and bad are NOT deallocated; */
+/* they are reused for cdb and dca, respectively. Hence, any handles that */
+/* may have held the original triangles are still valid, although not */
+/* directed as they were before. */
+/* */
+/* Upon completion of this routine, the `flipedge' handle holds the edge */
+/* cd of triangle cdb, and is directed up, from vertex c to vertex d. */
+/* (Hence, the two triangles have rotated clockwise.) */
+/* */
+/* WARNING: This transformation is geometrically valid only if the */
+/* quadrilateral adbc is convex. Furthermore, this transformation is */
+/* valid only if there is not a subsegment between the triangles abc and */
+/* bad. This routine does not check either of these preconditions, and */
+/* it is the responsibility of the calling routine to ensure that they are */
+/* met. If they are not, the streets shall be filled with wailing and */
+/* gnashing of teeth. */
+/* */
+/*****************************************************************************/
+
+void unflip(struct mesh *m, struct behavior *b, struct otri *flipedge) {
+ struct otri botleft, botright;
+ struct otri topleft, topright;
+ struct otri top;
+ struct otri botlcasing, botrcasing;
+ struct otri toplcasing, toprcasing;
+ struct osub botlsubseg, botrsubseg;
+ struct osub toplsubseg, toprsubseg;
+ vertex leftvertex, rightvertex, botvertex;
+ vertex farvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ /* Identify the vertices of the quadrilateral. */
+ org(*flipedge, rightvertex);
+ dest(*flipedge, leftvertex);
+ apex(*flipedge, botvertex);
+ sym(*flipedge, top);
+#ifdef SELF_CHECK
+ if (top.tri == m->dummytri)
+ {
+ printf("Internal error in unflip(): Attempt to flip on boundary.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ if (m->checksegments)
+ {
+ tspivot(*flipedge, toplsubseg);
+ if (toplsubseg.ss != m->dummysub)
+ {
+ printf("Internal error in unflip(): Attempt to flip a subsegment.\n");
+ lnextself(*flipedge);
+ return;
+ }
+ }
+#endif /* SELF_CHECK */
+ apex(top, farvertex);
+
+ /* Identify the casing of the quadrilateral. */
+ lprev(top, topleft);
+ sym(topleft, toplcasing);
+ lnext(top, topright);
+ sym(topright, toprcasing);
+ lnext(*flipedge, botleft);
+ sym(botleft, botlcasing);
+ lprev(*flipedge, botright);
+ sym(botright, botrcasing);
+ /* Rotate the quadrilateral one-quarter turn clockwise. */
+ bond(topleft, toprcasing);
+ bond(botleft, toplcasing);
+ bond(botright, botlcasing);
+ bond(topright, botrcasing);
+
+ if (m->checksegments) {
+ /* Check for subsegments and rebond them to the quadrilateral. */
+ tspivot(topleft, toplsubseg);
+ tspivot(botleft, botlsubseg);
+ tspivot(botright, botrsubseg);
+ tspivot(topright, toprsubseg);
+ if (toplsubseg.ss == m->dummysub) {
+ tsdissolve(botleft);
+ }
+ else {
+ tsbond(botleft, toplsubseg);
+ }
+ if (botlsubseg.ss == m->dummysub) {
+ tsdissolve(botright);
+ }
+ else {
+ tsbond(botright, botlsubseg);
+ }
+ if (botrsubseg.ss == m->dummysub) {
+ tsdissolve(topright);
+ }
+ else {
+ tsbond(topright, botrsubseg);
+ }
+ if (toprsubseg.ss == m->dummysub) {
+ tsdissolve(topleft);
+ }
+ else {
+ tsbond(topleft, toprsubseg);
+ }
+ }
+
+ /* New vertex assignments for the rotated quadrilateral. */
+ setorg(*flipedge, botvertex);
+ setdest(*flipedge, farvertex);
+ setapex(*flipedge, leftvertex);
+ setorg(top, farvertex);
+ setdest(top, botvertex);
+ setapex(top, rightvertex);
+ if (b->verbose > 2) {
+ printf(" Edge unflip results in left ");
+ printtriangle(m, b, flipedge);
+ printf(" and right ");
+ printtriangle(m, b, &top);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* insertvertex() Insert a vertex into a Delaunay triangulation, */
+/* performing flips as necessary to maintain the Delaunay */
+/* property. */
+/* */
+/* The point `insertvertex' is located. If `searchtri.tri' is not NULL, */
+/* the search for the containing triangle begins from `searchtri'. If */
+/* `searchtri.tri' is NULL, a full point location procedure is called. */
+/* If `insertvertex' is found inside a triangle, the triangle is split into */
+/* three; if `insertvertex' lies on an edge, the edge is split in two, */
+/* thereby splitting the two adjacent triangles into four. Edge flips are */
+/* used to restore the Delaunay property. If `insertvertex' lies on an */
+/* existing vertex, no action is taken, and the value DUPLICATEVERTEX is */
+/* returned. On return, `searchtri' is set to a handle whose origin is the */
+/* existing vertex. */
+/* */
+/* Normally, the parameter `splitseg' is set to NULL, implying that no */
+/* subsegment should be split. In this case, if `insertvertex' is found to */
+/* lie on a segment, no action is taken, and the value VIOLATINGVERTEX is */
+/* returned. On return, `searchtri' is set to a handle whose primary edge */
+/* is the violated subsegment. */
+/* */
+/* If the calling routine wishes to split a subsegment by inserting a */
+/* vertex in it, the parameter `splitseg' should be that subsegment. In */
+/* this case, `searchtri' MUST be the triangle handle reached by pivoting */
+/* from that subsegment; no point location is done. */
+/* */
+/* `segmentflaws' and `triflaws' are flags that indicate whether or not */
+/* there should be checks for the creation of encroached subsegments or bad */
+/* quality triangles. If a newly inserted vertex encroaches upon */
+/* subsegments, these subsegments are added to the list of subsegments to */
+/* be split if `segmentflaws' is set. If bad triangles are created, these */
+/* are added to the queue if `triflaws' is set. */
+/* */
+/* If a duplicate vertex or violated segment does not prevent the vertex */
+/* from being inserted, the return value will be ENCROACHINGVERTEX if the */
+/* vertex encroaches upon a subsegment (and checking is enabled), or */
+/* SUCCESSFULVERTEX otherwise. In either case, `searchtri' is set to a */
+/* handle whose origin is the newly inserted vertex. */
+/* */
+/* insertvertex() does not use flip() for reasons of speed; some */
+/* information can be reused from edge flip to edge flip, like the */
+/* locations of subsegments. */
+/* */
+/*****************************************************************************/
+
+enum insertvertexresult insertvertex(struct mesh *m, struct behavior *b, vertex newvertex,
+ struct otri *searchtri, struct osub *splitseg, int segmentflaws, int triflaws) {
+ struct otri horiz;
+ struct otri top;
+ struct otri botleft, botright;
+ struct otri topleft, topright;
+ struct otri newbotleft, newbotright;
+ struct otri newtopright;
+ struct otri botlcasing, botrcasing;
+ struct otri toplcasing, toprcasing;
+ struct otri testtri;
+ struct osub botlsubseg, botrsubseg;
+ struct osub toplsubseg, toprsubseg;
+ struct osub brokensubseg;
+ struct osub checksubseg;
+ struct osub rightsubseg;
+ struct osub newsubseg;
+ struct badsubseg *encroached;
+ struct flipstacker *newflip;
+ vertex first;
+ vertex leftvertex, rightvertex, botvertex, topvertex, farvertex;
+ vertex segmentorg, segmentdest;
+ REAL attrib;
+ REAL area;
+ enum insertvertexresult success;
+ enum locateresult intersect;
+ int doflip;
+ int mirrorflag;
+ int enq;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by spivot() and tspivot(). */
+
+ if (b->verbose > 1) {
+ printf(" Inserting (%.12g, %.12g).\n", newvertex[0], newvertex[1]);
+ }
+
+ if (splitseg == (struct osub *) NULL) {
+ /* Find the location of the vertex to be inserted. Check if a good */
+ /* starting triangle has already been provided by the caller. */
+ if (searchtri->tri == m->dummytri) {
+ /* Find a boundary triangle. */
+ horiz.tri = m->dummytri;
+ horiz.orient = 0;
+ symself(horiz);
+ /* Search for a triangle containing `newvertex'. */
+ intersect = locate(m, b, newvertex, &horiz);
+ }
+ else {
+ /* Start searching from the triangle provided by the caller. */
+ otricopy(*searchtri, horiz);
+ intersect = preciselocate(m, b, newvertex, &horiz, 1);
+ }
+ }
+ else {
+ /* The calling routine provides the subsegment in which */
+ /* the vertex is inserted. */
+ otricopy(*searchtri, horiz);
+ intersect = ONEDGE;
+ }
+
+ if (intersect == ONVERTEX) {
+ /* There's already a vertex there. Return in `searchtri' a triangle */
+ /* whose origin is the existing vertex. */
+ otricopy(horiz, *searchtri);
+ otricopy(horiz, m->recenttri);
+ return DUPLICATEVERTEX;
+ }
+ if ((intersect == ONEDGE) || (intersect == OUTSIDE)) {
+ /* The vertex falls on an edge or boundary. */
+ if (m->checksegments && (splitseg == (struct osub *) NULL)) {
+ /* Check whether the vertex falls on a subsegment. */
+ tspivot(horiz, brokensubseg);
+ if (brokensubseg.ss != m->dummysub) {
+ /* The vertex falls on a subsegment, and hence will not be inserted. */
+ if (segmentflaws) {
+ enq = b->nobisect != 2;
+ if (enq && (b->nobisect == 1)) {
+ /* This subsegment may be split only if it is an */
+ /* internal boundary. */
+ sym(horiz, testtri);
+ enq = testtri.tri != m->dummytri;
+ }
+ if (enq) {
+ /* Add the subsegment to the list of encroached subsegments. */
+ encroached = (struct badsubseg *) poolalloc(&m->badsubsegs);
+ encroached->encsubseg = sencode(brokensubseg);
+ sorg(brokensubseg, encroached->subsegorg);
+ sdest(brokensubseg, encroached->subsegdest);
+ if (b->verbose > 2) {
+ printf(
+ " Queueing encroached subsegment (%.12g, %.12g) (%.12g, %.12g).\n", encroached->subsegorg[0], encroached->subsegorg[1], encroached->subsegdest[0], encroached->subsegdest[1]);
+ }
+ }
+ }
+ /* Return a handle whose primary edge contains the vertex, */
+ /* which has not been inserted. */
+ otricopy(horiz, *searchtri);
+ otricopy(horiz, m->recenttri);
+ return VIOLATINGVERTEX;
+ }
+ }
+
+ /* Insert the vertex on an edge, dividing one triangle into two (if */
+ /* the edge lies on a boundary) or two triangles into four. */
+ lprev(horiz, botright);
+ sym(botright, botrcasing);
+ sym(horiz, topright);
+ /* Is there a second triangle? (Or does this edge lie on a boundary?) */
+ mirrorflag = topright.tri != m->dummytri;
+ if (mirrorflag) {
+ lnextself(topright);
+ sym(topright, toprcasing);
+ maketriangle(m, b, &newtopright);
+ }
+ else {
+ /* Splitting a boundary edge increases the number of boundary edges. */
+ m->hullsize++;
+ }
+ maketriangle(m, b, &newbotright);
+
+ /* Set the vertices of changed and new triangles. */
+ org(horiz, rightvertex);
+ dest(horiz, leftvertex);
+ apex(horiz, botvertex);
+ setorg(newbotright, botvertex);
+ setdest(newbotright, rightvertex);
+ setapex(newbotright, newvertex);
+ setorg(horiz, newvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Set the element attributes of a new triangle. */
+ setelemattribute(newbotright, i, elemattribute(botright, i));
+ }
+ if (b->vararea) {
+ /* Set the area constraint of a new triangle. */
+ setareabound(newbotright, areabound(botright));
+ }
+ if (mirrorflag) {
+ dest(topright, topvertex);
+ setorg(newtopright, rightvertex);
+ setdest(newtopright, topvertex);
+ setapex(newtopright, newvertex);
+ setorg(topright, newvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Set the element attributes of another new triangle. */
+ setelemattribute(newtopright, i, elemattribute(topright, i));
+ }
+ if (b->vararea) {
+ /* Set the area constraint of another new triangle. */
+ setareabound(newtopright, areabound(topright));
+ }
+ }
+
+ /* There may be subsegments that need to be bonded */
+ /* to the new triangle(s). */
+ if (m->checksegments) {
+ tspivot(botright, botrsubseg);
+ if (botrsubseg.ss != m->dummysub) {
+ tsdissolve(botright);
+ tsbond(newbotright, botrsubseg);
+ }
+ if (mirrorflag) {
+ tspivot(topright, toprsubseg);
+ if (toprsubseg.ss != m->dummysub) {
+ tsdissolve(topright);
+ tsbond(newtopright, toprsubseg);
+ }
+ }
+ }
+
+ /* Bond the new triangle(s) to the surrounding triangles. */
+ bond(newbotright, botrcasing);
+ lprevself(newbotright);
+ bond(newbotright, botright);
+ lprevself(newbotright);
+ if (mirrorflag) {
+ bond(newtopright, toprcasing);
+ lnextself(newtopright);
+ bond(newtopright, topright);
+ lnextself(newtopright);
+ bond(newtopright, newbotright);
+ }
+
+ if (splitseg != (struct osub *) NULL) {
+ /* Split the subsegment into two. */
+ setsdest(*splitseg, newvertex);
+ segorg(*splitseg, segmentorg);
+ segdest(*splitseg, segmentdest);
+ ssymself(*splitseg);
+ spivot(*splitseg, rightsubseg);
+ insertsubseg(m, b, &newbotright, mark(*splitseg));
+ tspivot(newbotright, newsubseg);
+ setsegorg(newsubseg, segmentorg);
+ setsegdest(newsubseg, segmentdest);
+ sbond(*splitseg, newsubseg);
+ ssymself(newsubseg);
+ sbond(newsubseg, rightsubseg);
+ ssymself(*splitseg);
+ /* Transfer the subsegment's boundary marker to the vertex */
+ /* if required. */
+ if (vertexmark(newvertex) == 0) {
+ setvertexmark(newvertex, mark(*splitseg));
+ }
+ }
+
+ if (m->checkquality) {
+ poolrestart(&m->flipstackers);
+ m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+ m->lastflip->flippedtri = encode(horiz);
+ m->lastflip->prevflip = (struct flipstacker *) &insertvertex;
+ }
+
+#ifdef SELF_CHECK
+ if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle prior to edge vertex insertion (bottom).\n");
+ }
+ if (mirrorflag)
+ {
+ if (counterclockwise(m, b, leftvertex, rightvertex, topvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to edge vertex insertion (top).\n");
+ }
+ if (counterclockwise(m, b, rightvertex, topvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (top right).\n");
+ }
+ if (counterclockwise(m, b, topvertex, leftvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (top left).\n");
+ }
+ }
+ if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (bottom left).\n");
+ }
+ if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(
+ " Clockwise triangle after edge vertex insertion (bottom right).\n");
+ }
+#endif /* SELF_CHECK */
+ if (b->verbose > 2) {
+ printf(" Updating bottom left ");
+ printtriangle(m, b, &botright);
+ if (mirrorflag) {
+ printf(" Updating top left ");
+ printtriangle(m, b, &topright);
+ printf(" Creating top right ");
+ printtriangle(m, b, &newtopright);
+ }
+ printf(" Creating bottom right ");
+ printtriangle(m, b, &newbotright);
+ }
+
+ /* Position `horiz' on the first edge to check for */
+ /* the Delaunay property. */
+ lnextself(horiz);
+ }
+ else {
+ /* Insert the vertex in a triangle, splitting it into three. */
+ lnext(horiz, botleft);
+ lprev(horiz, botright);
+ sym(botleft, botlcasing);
+ sym(botright, botrcasing);
+ maketriangle(m, b, &newbotleft);
+ maketriangle(m, b, &newbotright);
+
+ /* Set the vertices of changed and new triangles. */
+ org(horiz, rightvertex);
+ dest(horiz, leftvertex);
+ apex(horiz, botvertex);
+ setorg(newbotleft, leftvertex);
+ setdest(newbotleft, botvertex);
+ setapex(newbotleft, newvertex);
+ setorg(newbotright, botvertex);
+ setdest(newbotright, rightvertex);
+ setapex(newbotright, newvertex);
+ setapex(horiz, newvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Set the element attributes of the new triangles. */
+ attrib = elemattribute(horiz, i);
+ setelemattribute(newbotleft, i, attrib);
+ setelemattribute(newbotright, i, attrib);
+ }
+ if (b->vararea) {
+ /* Set the area constraint of the new triangles. */
+ area = areabound(horiz);
+ setareabound(newbotleft, area);
+ setareabound(newbotright, area);
+ }
+
+ /* There may be subsegments that need to be bonded */
+ /* to the new triangles. */
+ if (m->checksegments) {
+ tspivot(botleft, botlsubseg);
+ if (botlsubseg.ss != m->dummysub) {
+ tsdissolve(botleft);
+ tsbond(newbotleft, botlsubseg);
+ }
+ tspivot(botright, botrsubseg);
+ if (botrsubseg.ss != m->dummysub) {
+ tsdissolve(botright);
+ tsbond(newbotright, botrsubseg);
+ }
+ }
+
+ /* Bond the new triangles to the surrounding triangles. */
+ bond(newbotleft, botlcasing);
+ bond(newbotright, botrcasing);
+ lnextself(newbotleft);
+ lprevself(newbotright);
+ bond(newbotleft, newbotright);
+ lnextself(newbotleft);
+ bond(botleft, newbotleft);
+ lprevself(newbotright);
+ bond(botright, newbotright);
+
+ if (m->checkquality) {
+ poolrestart(&m->flipstackers);
+ m->lastflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+ m->lastflip->flippedtri = encode(horiz);
+ m->lastflip->prevflip = (struct flipstacker *) NULL;
+ }
+
+#ifdef SELF_CHECK
+ if (counterclockwise(m, b, rightvertex, leftvertex, botvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to vertex insertion.\n");
+ }
+ if (counterclockwise(m, b, rightvertex, leftvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after vertex insertion (top).\n");
+ }
+ if (counterclockwise(m, b, leftvertex, botvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after vertex insertion (left).\n");
+ }
+ if (counterclockwise(m, b, botvertex, rightvertex, newvertex) < 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after vertex insertion (right).\n");
+ }
+#endif /* SELF_CHECK */
+ if (b->verbose > 2) {
+ printf(" Updating top ");
+ printtriangle(m, b, &horiz);
+ printf(" Creating left ");
+ printtriangle(m, b, &newbotleft);
+ printf(" Creating right ");
+ printtriangle(m, b, &newbotright);
+ }
+ }
+
+ /* The insertion is successful by default, unless an encroached */
+ /* subsegment is found. */
+ success = SUCCESSFULVERTEX;
+ /* Circle around the newly inserted vertex, checking each edge opposite */
+ /* it for the Delaunay property. Non-Delaunay edges are flipped. */
+ /* `horiz' is always the edge being checked. `first' marks where to */
+ /* stop circling. */
+ org(horiz, first);
+ rightvertex = first;
+ dest(horiz, leftvertex);
+ /* Circle until finished. */
+ while (1) {
+ /* By default, the edge will be flipped. */
+ doflip = 1;
+
+ if (m->checksegments) {
+ /* Check for a subsegment, which cannot be flipped. */
+ tspivot(horiz, checksubseg);
+ if (checksubseg.ss != m->dummysub) {
+ /* The edge is a subsegment and cannot be flipped. */
+ doflip = 0;
+#ifndef CDT_ONLY
+ if (segmentflaws)
+ {
+ /* Does the new vertex encroach upon this subsegment? */
+ if (checkseg4encroach(m, b, &checksubseg))
+ {
+ success = ENCROACHINGVERTEX;
+ }
+ }
+#endif /* not CDT_ONLY */
+ }
+ }
+
+ if (doflip) {
+ /* Check if the edge is a boundary edge. */
+ sym(horiz, top);
+ if (top.tri == m->dummytri) {
+ /* The edge is a boundary edge and cannot be flipped. */
+ doflip = 0;
+ }
+ else {
+ /* Find the vertex on the other side of the edge. */
+ apex(top, farvertex);
+ /* In the incremental Delaunay triangulation algorithm, any of */
+ /* `leftvertex', `rightvertex', and `farvertex' could be vertices */
+ /* of the triangular bounding box. These vertices must be */
+ /* treated as if they are infinitely distant, even though their */
+ /* "coordinates" are not. */
+ if ((leftvertex == m->infvertex1) || (leftvertex == m->infvertex2)
+ || (leftvertex == m->infvertex3)) {
+ /* `leftvertex' is infinitely distant. Check the convexity of */
+ /* the boundary of the triangulation. 'farvertex' might be */
+ /* infinite as well, but trust me, this same condition should */
+ /* be applied. */
+ doflip = counterclockwise(m, b, newvertex, rightvertex, farvertex) > 0.0;
+ }
+ else if ((rightvertex == m->infvertex1) || (rightvertex == m->infvertex2)
+ || (rightvertex == m->infvertex3)) {
+ /* `rightvertex' is infinitely distant. Check the convexity of */
+ /* the boundary of the triangulation. 'farvertex' might be */
+ /* infinite as well, but trust me, this same condition should */
+ /* be applied. */
+ doflip = counterclockwise(m, b, farvertex, leftvertex, newvertex) > 0.0;
+ }
+ else if ((farvertex == m->infvertex1) || (farvertex == m->infvertex2)
+ || (farvertex == m->infvertex3)) {
+ /* `farvertex' is infinitely distant and cannot be inside */
+ /* the circumcircle of the triangle `horiz'. */
+ doflip = 0;
+ }
+ else {
+ /* Test whether the edge is locally Delaunay. */
+ doflip = incircle(m, b, leftvertex, newvertex, rightvertex, farvertex) > 0.0;
+ }
+ if (doflip) {
+ /* We made it! Flip the edge `horiz' by rotating its containing */
+ /* quadrilateral (the two triangles adjacent to `horiz'). */
+ /* Identify the casing of the quadrilateral. */
+ lprev(top, topleft);
+ sym(topleft, toplcasing);
+ lnext(top, topright);
+ sym(topright, toprcasing);
+ lnext(horiz, botleft);
+ sym(botleft, botlcasing);
+ lprev(horiz, botright);
+ sym(botright, botrcasing);
+ /* Rotate the quadrilateral one-quarter turn counterclockwise. */
+ bond(topleft, botlcasing);
+ bond(botleft, botrcasing);
+ bond(botright, toprcasing);
+ bond(topright, toplcasing);
+ if (m->checksegments) {
+ /* Check for subsegments and rebond them to the quadrilateral. */
+ tspivot(topleft, toplsubseg);
+ tspivot(botleft, botlsubseg);
+ tspivot(botright, botrsubseg);
+ tspivot(topright, toprsubseg);
+ if (toplsubseg.ss == m->dummysub) {
+ tsdissolve(topright);
+ }
+ else {
+ tsbond(topright, toplsubseg);
+ }
+ if (botlsubseg.ss == m->dummysub) {
+ tsdissolve(topleft);
+ }
+ else {
+ tsbond(topleft, botlsubseg);
+ }
+ if (botrsubseg.ss == m->dummysub) {
+ tsdissolve(botleft);
+ }
+ else {
+ tsbond(botleft, botrsubseg);
+ }
+ if (toprsubseg.ss == m->dummysub) {
+ tsdissolve(botright);
+ }
+ else {
+ tsbond(botright, toprsubseg);
+ }
+ }
+ /* New vertex assignments for the rotated quadrilateral. */
+ setorg(horiz, farvertex);
+ setdest(horiz, newvertex);
+ setapex(horiz, rightvertex);
+ setorg(top, newvertex);
+ setdest(top, farvertex);
+ setapex(top, leftvertex);
+ for (i = 0; i < m->eextras; i++) {
+ /* Take the average of the two triangles' attributes. */
+ attrib = 0.5 * (elemattribute(top, i) + elemattribute(horiz, i));
+ setelemattribute(top, i, attrib);
+ setelemattribute(horiz, i, attrib);
+ }
+ if (b->vararea) {
+ if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) {
+ area = -1.0;
+ }
+ else {
+ /* Take the average of the two triangles' area constraints. */
+ /* This prevents small area constraints from migrating a */
+ /* long, long way from their original location due to flips. */
+ area = 0.5 * (areabound(top) + areabound(horiz));
+ }
+ setareabound(top, area);
+ setareabound(horiz, area);
+ }
+
+ if (m->checkquality) {
+ newflip = (struct flipstacker *) poolalloc(&m->flipstackers);
+ newflip->flippedtri = encode(horiz);
+ newflip->prevflip = m->lastflip;
+ m->lastflip = newflip;
+ }
+
+#ifdef SELF_CHECK
+ if (newvertex != (vertex) NULL)
+ {
+ if (counterclockwise(m, b, leftvertex, newvertex, rightvertex) <
+ 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to edge flip (bottom).\n");
+ }
+ /* The following test has been removed because constrainededge() */
+ /* sometimes generates inverted triangles that insertvertex() */
+ /* removes. */
+ /*
+ if (counterclockwise(m, b, rightvertex, farvertex, leftvertex) <
+ 0.0) {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle prior to edge flip (top).\n");
+ }
+ */
+ if (counterclockwise(m, b, farvertex, leftvertex, newvertex) <
+ 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after edge flip (left).\n");
+ }
+ if (counterclockwise(m, b, newvertex, rightvertex, farvertex) <
+ 0.0)
+ {
+ printf("Internal error in insertvertex():\n");
+ printf(" Clockwise triangle after edge flip (right).\n");
+ }
+ }
+#endif /* SELF_CHECK */
+ if (b->verbose > 2) {
+ printf(" Edge flip results in left ");
+ lnextself(topleft);
+ printtriangle(m, b, &topleft);
+ printf(" and right ");
+ printtriangle(m, b, &horiz);
+ }
+ /* On the next iterations, consider the two edges that were */
+ /* exposed (this is, are now visible to the newly inserted */
+ /* vertex) by the edge flip. */
+ lprevself(horiz);
+ leftvertex = farvertex;
+ }
+ }
+ }
+ if (!doflip) {
+ /* The handle `horiz' is accepted as locally Delaunay. */
+#ifndef CDT_ONLY
+ if (triflaws)
+ {
+ /* Check the triangle `horiz' for quality. */
+ testtriangle(m, b, &horiz);
+ }
+#endif /* not CDT_ONLY */
+ /* Look for the next edge around the newly inserted vertex. */
+ lnextself(horiz);
+ sym(horiz, testtri);
+ /* Check for finishing a complete revolution about the new vertex, or */
+ /* falling outside of the triangulation. The latter will happen */
+ /* when a vertex is inserted at a boundary. */
+ if ((leftvertex == first) || (testtri.tri == m->dummytri)) {
+ /* We're done. Return a triangle whose origin is the new vertex. */
+ lnext(horiz, *searchtri);
+ lnext(horiz, m->recenttri);
+ return success;
+ }
+ /* Finish finding the next edge around the newly inserted vertex. */
+ lnext(testtri, horiz);
+ rightvertex = leftvertex;
+ dest(horiz, leftvertex);
+ }
+ }
+}
+
+/********* Divide-and-conquer Delaunay triangulation begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* The divide-and-conquer bounding box */
+/* */
+/* I originally implemented the divide-and-conquer and incremental Delaunay */
+/* triangulations using the edge-based data structure presented by Guibas */
+/* and Stolfi. Switching to a triangle-based data structure doubled the */
+/* speed. However, I had to think of a few extra tricks to maintain the */
+/* elegance of the original algorithms. */
+/* */
+/* The "bounding box" used by my variant of the divide-and-conquer */
+/* algorithm uses one triangle for each edge of the convex hull of the */
+/* triangulation. These bounding triangles all share a common apical */
+/* vertex, which is represented by NULL and which represents nothing. */
+/* The bounding triangles are linked in a circular fan about this NULL */
+/* vertex, and the edges on the convex hull of the triangulation appear */
+/* opposite the NULL vertex. You might find it easiest to imagine that */
+/* the NULL vertex is a point in 3D space behind the center of the */
+/* triangulation, and that the bounding triangles form a sort of cone. */
+/* */
+/* This bounding box makes it easy to represent degenerate cases. For */
+/* instance, the triangulation of two vertices is a single edge. This edge */
+/* is represented by two bounding box triangles, one on each "side" of the */
+/* edge. These triangles are also linked together in a fan about the NULL */
+/* vertex. */
+/* */
+/* The bounding box also makes it easy to traverse the convex hull, as the */
+/* divide-and-conquer algorithm needs to do. */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* */
+/* vertexsort() Sort an array of vertices by x-coordinate, using the */
+/* y-coordinate as a secondary key. */
+/* */
+/* Uses quicksort. Randomized O(n log n) time. No, I did not make any of */
+/* the usual quicksort mistakes. */
+/* */
+/*****************************************************************************/
+
+void vertexsort(vertex *sortarray, int arraysize) {
+ int left, right;
+ int pivot;
+ REAL pivotx, pivoty;
+ vertex temp;
+
+ if (arraysize == 2) {
+ /* Recursive base case. */
+ if ((sortarray[0][0] > sortarray[1][0])
+ || ((sortarray[0][0] == sortarray[1][0]) && (sortarray[0][1] > sortarray[1][1]))) {
+ temp = sortarray[1];
+ sortarray[1] = sortarray[0];
+ sortarray[0] = temp;
+ }
+ return;
+ }
+ /* Choose a random pivot to split the array. */
+ pivot = (int) randomnation((unsigned int) arraysize);
+ pivotx = sortarray[pivot][0];
+ pivoty = sortarray[pivot][1];
+ /* Split the array. */
+ left = -1;
+ right = arraysize;
+ while (left < right) {
+ /* Search for a vertex whose x-coordinate is too large for the left. */
+ do {
+ left++;
+ } while ((left <= right)
+ && ((sortarray[left][0] < pivotx)
+ || ((sortarray[left][0] == pivotx) && (sortarray[left][1] < pivoty))));
+ /* Search for a vertex whose x-coordinate is too small for the right. */
+ do {
+ right--;
+ } while ((left <= right)
+ && ((sortarray[right][0] > pivotx)
+ || ((sortarray[right][0] == pivotx) && (sortarray[right][1] > pivoty))));
+ if (left < right) {
+ /* Swap the left and right vertices. */
+ temp = sortarray[left];
+ sortarray[left] = sortarray[right];
+ sortarray[right] = temp;
+ }
+ }
+ if (left > 1) {
+ /* Recursively sort the left subset. */
+ vertexsort(sortarray, left);
+ }
+ if (right < arraysize - 2) {
+ /* Recursively sort the right subset. */
+ vertexsort(&sortarray[right + 1], arraysize - right - 1);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* vertexmedian() An order statistic algorithm, almost. Shuffles an */
+/* array of vertices so that the first `median' vertices */
+/* occur lexicographically before the remaining vertices. */
+/* */
+/* Uses the x-coordinate as the primary key if axis == 0; the y-coordinate */
+/* if axis == 1. Very similar to the vertexsort() procedure, but runs in */
+/* randomized linear time. */
+/* */
+/*****************************************************************************/
+
+void vertexmedian(vertex *sortarray, int arraysize, int median, int axis) {
+ int left, right;
+ int pivot;
+ REAL pivot1, pivot2;
+ vertex temp;
+
+ if (arraysize == 2) {
+ /* Recursive base case. */
+ if ((sortarray[0][axis] > sortarray[1][axis])
+ || ((sortarray[0][axis] == sortarray[1][axis])
+ && (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) {
+ temp = sortarray[1];
+ sortarray[1] = sortarray[0];
+ sortarray[0] = temp;
+ }
+ return;
+ }
+ /* Choose a random pivot to split the array. */
+ pivot = (int) randomnation((unsigned int) arraysize);
+ pivot1 = sortarray[pivot][axis];
+ pivot2 = sortarray[pivot][1 - axis];
+ /* Split the array. */
+ left = -1;
+ right = arraysize;
+ while (left < right) {
+ /* Search for a vertex whose x-coordinate is too large for the left. */
+ do {
+ left++;
+ } while ((left <= right)
+ && ((sortarray[left][axis] < pivot1)
+ || ((sortarray[left][axis] == pivot1) && (sortarray[left][1 - axis] < pivot2))));
+ /* Search for a vertex whose x-coordinate is too small for the right. */
+ do {
+ right--;
+ } while ((left <= right)
+ && ((sortarray[right][axis] > pivot1)
+ || ((sortarray[right][axis] == pivot1) && (sortarray[right][1 - axis] > pivot2))));
+ if (left < right) {
+ /* Swap the left and right vertices. */
+ temp = sortarray[left];
+ sortarray[left] = sortarray[right];
+ sortarray[right] = temp;
+ }
+ }
+ /* Unlike in vertexsort(), at most one of the following */
+ /* conditionals is true. */
+ if (left > median) {
+ /* Recursively shuffle the left subset. */
+ vertexmedian(sortarray, left, median, axis);
+ }
+ if (right < median - 1) {
+ /* Recursively shuffle the right subset. */
+ vertexmedian(&sortarray[right + 1], arraysize - right - 1, median - right - 1, axis);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* alternateaxes() Sorts the vertices as appropriate for the divide-and- */
+/* conquer algorithm with alternating cuts. */
+/* */
+/* Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1. */
+/* For the base case, subsets containing only two or three vertices are */
+/* always sorted by x-coordinate. */
+/* */
+/*****************************************************************************/
+
+void alternateaxes(vertex *sortarray, int arraysize, int axis) {
+ int divider;
+
+ divider = arraysize >> 1;
+ if (arraysize <= 3) {
+ /* Recursive base case: subsets of two or three vertices will be */
+ /* handled specially, and should always be sorted by x-coordinate. */
+ axis = 0;
+ }
+ /* Partition with a horizontal or vertical cut. */
+ vertexmedian(sortarray, arraysize, divider, axis);
+ /* Recursively partition the subsets with a cross cut. */
+ if (arraysize - divider >= 2) {
+ if (divider >= 2) {
+ alternateaxes(sortarray, divider, 1 - axis);
+ }
+ alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* mergehulls() Merge two adjacent Delaunay triangulations into a */
+/* single Delaunay triangulation. */
+/* */
+/* This is similar to the algorithm given by Guibas and Stolfi, but uses */
+/* a triangle-based, rather than edge-based, data structure. */
+/* */
+/* The algorithm walks up the gap between the two triangulations, knitting */
+/* them together. As they are merged, some of their bounding triangles */
+/* are converted into real triangles of the triangulation. The procedure */
+/* pulls each hull's bounding triangles apart, then knits them together */
+/* like the teeth of two gears. The Delaunay property determines, at each */
+/* step, whether the next "tooth" is a bounding triangle of the left hull */
+/* or the right. When a bounding triangle becomes real, its apex is */
+/* changed from NULL to a real vertex. */
+/* */
+/* Only two new triangles need to be allocated. These become new bounding */
+/* triangles at the top and bottom of the seam. They are used to connect */
+/* the remaining bounding triangles (those that have not been converted */
+/* into real triangles) into a single fan. */
+/* */
+/* On entry, `farleft' and `innerleft' are bounding triangles of the left */
+/* triangulation. The origin of `farleft' is the leftmost vertex, and */
+/* the destination of `innerleft' is the rightmost vertex of the */
+/* triangulation. Similarly, `innerright' and `farright' are bounding */
+/* triangles of the right triangulation. The origin of `innerright' and */
+/* destination of `farright' are the leftmost and rightmost vertices. */
+/* */
+/* On completion, the origin of `farleft' is the leftmost vertex of the */
+/* merged triangulation, and the destination of `farright' is the rightmost */
+/* vertex. */
+/* */
+/*****************************************************************************/
+
+void mergehulls(struct mesh *m, struct behavior *b, struct otri *farleft, struct otri *innerleft,
+ struct otri *innerright, struct otri *farright, int axis) {
+ struct otri leftcand, rightcand;
+ struct otri baseedge;
+ struct otri nextedge;
+ struct otri sidecasing, topcasing, outercasing;
+ struct otri checkedge;
+ vertex innerleftdest;
+ vertex innerrightorg;
+ vertex innerleftapex, innerrightapex;
+ vertex farleftpt, farrightpt;
+ vertex farleftapex, farrightapex;
+ vertex lowerleft, lowerright;
+ vertex upperleft, upperright;
+ vertex nextapex;
+ vertex checkvertex;
+ int changemade;
+ int badedge;
+ int leftfinished, rightfinished;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ dest(*innerleft, innerleftdest);
+ apex(*innerleft, innerleftapex);
+ org(*innerright, innerrightorg);
+ apex(*innerright, innerrightapex);
+ /* Special treatment for horizontal cuts. */
+ if (b->dwyer && (axis == 1)) {
+ org(*farleft, farleftpt);
+ apex(*farleft, farleftapex);
+ dest(*farright, farrightpt);
+ apex(*farright, farrightapex);
+ /* The pointers to the extremal vertices are shifted to point to the */
+ /* topmost and bottommost vertex of each hull, rather than the */
+ /* leftmost and rightmost vertices. */
+ while (farleftapex[1] < farleftpt[1]) {
+ lnextself(*farleft);
+ symself(*farleft);
+ farleftpt = farleftapex;
+ apex(*farleft, farleftapex);
+ }
+ sym(*innerleft, checkedge);
+ apex(checkedge, checkvertex);
+ while (checkvertex[1] > innerleftdest[1]) {
+ lnext(checkedge, *innerleft);
+ innerleftapex = innerleftdest;
+ innerleftdest = checkvertex;
+ sym(*innerleft, checkedge);
+ apex(checkedge, checkvertex);
+ }
+ while (innerrightapex[1] < innerrightorg[1]) {
+ lnextself(*innerright);
+ symself(*innerright);
+ innerrightorg = innerrightapex;
+ apex(*innerright, innerrightapex);
+ }
+ sym(*farright, checkedge);
+ apex(checkedge, checkvertex);
+ while (checkvertex[1] > farrightpt[1]) {
+ lnext(checkedge, *farright);
+ farrightapex = farrightpt;
+ farrightpt = checkvertex;
+ sym(*farright, checkedge);
+ apex(checkedge, checkvertex);
+ }
+ }
+ /* Find a line tangent to and below both hulls. */
+ do {
+ changemade = 0;
+ /* Make innerleftdest the "bottommost" vertex of the left hull. */
+ if (counterclockwise(m, b, innerleftdest, innerleftapex, innerrightorg) > 0.0) {
+ lprevself(*innerleft);
+ symself(*innerleft);
+ innerleftdest = innerleftapex;
+ apex(*innerleft, innerleftapex);
+ changemade = 1;
+ }
+ /* Make innerrightorg the "bottommost" vertex of the right hull. */
+ if (counterclockwise(m, b, innerrightapex, innerrightorg, innerleftdest) > 0.0) {
+ lnextself(*innerright);
+ symself(*innerright);
+ innerrightorg = innerrightapex;
+ apex(*innerright, innerrightapex);
+ changemade = 1;
+ }
+ } while (changemade);
+ /* Find the two candidates to be the next "gear tooth." */
+ sym(*innerleft, leftcand);
+ sym(*innerright, rightcand);
+ /* Create the bottom new bounding triangle. */
+ maketriangle(m, b, &baseedge);
+ /* Connect it to the bounding boxes of the left and right triangulations. */
+ bond(baseedge, *innerleft);
+ lnextself(baseedge);
+ bond(baseedge, *innerright);
+ lnextself(baseedge);
+ setorg(baseedge, innerrightorg);
+ setdest(baseedge, innerleftdest);
+ /* Apex is intentionally left NULL. */
+ if (b->verbose > 2) {
+ printf(" Creating base bounding ");
+ printtriangle(m, b, &baseedge);
+ }
+ /* Fix the extreme triangles if necessary. */
+ org(*farleft, farleftpt);
+ if (innerleftdest == farleftpt) {
+ lnext(baseedge, *farleft);
+ }
+ dest(*farright, farrightpt);
+ if (innerrightorg == farrightpt) {
+ lprev(baseedge, *farright);
+ }
+ /* The vertices of the current knitting edge. */
+ lowerleft = innerleftdest;
+ lowerright = innerrightorg;
+ /* The candidate vertices for knitting. */
+ apex(leftcand, upperleft);
+ apex(rightcand, upperright);
+ /* Walk up the gap between the two triangulations, knitting them together. */
+ while (1) {
+ /* Have we reached the top? (This isn't quite the right question, */
+ /* because even though the left triangulation might seem finished now, */
+ /* moving up on the right triangulation might reveal a new vertex of */
+ /* the left triangulation. And vice-versa.) */
+ leftfinished = counterclockwise(m, b, upperleft, lowerleft, lowerright) <= 0.0;
+ rightfinished = counterclockwise(m, b, upperright, lowerleft, lowerright) <= 0.0;
+ if (leftfinished && rightfinished) {
+ /* Create the top new bounding triangle. */
+ maketriangle(m, b, &nextedge);
+ setorg(nextedge, lowerleft);
+ setdest(nextedge, lowerright);
+ /* Apex is intentionally left NULL. */
+ /* Connect it to the bounding boxes of the two triangulations. */
+ bond(nextedge, baseedge);
+ lnextself(nextedge);
+ bond(nextedge, rightcand);
+ lnextself(nextedge);
+ bond(nextedge, leftcand);
+ if (b->verbose > 2) {
+ printf(" Creating top bounding ");
+ printtriangle(m, b, &nextedge);
+ }
+ /* Special treatment for horizontal cuts. */
+ if (b->dwyer && (axis == 1)) {
+ org(*farleft, farleftpt);
+ apex(*farleft, farleftapex);
+ dest(*farright, farrightpt);
+ apex(*farright, farrightapex);
+ sym(*farleft, checkedge);
+ apex(checkedge, checkvertex);
+ /* The pointers to the extremal vertices are restored to the */
+ /* leftmost and rightmost vertices (rather than topmost and */
+ /* bottommost). */
+ while (checkvertex[0] < farleftpt[0]) {
+ lprev(checkedge, *farleft);
+ farleftapex = farleftpt;
+ farleftpt = checkvertex;
+ sym(*farleft, checkedge);
+ apex(checkedge, checkvertex);
+ }
+ while (farrightapex[0] > farrightpt[0]) {
+ lprevself(*farright);
+ symself(*farright);
+ farrightpt = farrightapex;
+ apex(*farright, farrightapex);
+ }
+ }
+ return;
+ }
+ /* Consider eliminating edges from the left triangulation. */
+ if (!leftfinished) {
+ /* What vertex would be exposed if an edge were deleted? */
+ lprev(leftcand, nextedge);
+ symself(nextedge);
+ apex(nextedge, nextapex);
+ /* If nextapex is NULL, then no vertex would be exposed; the */
+ /* triangulation would have been eaten right through. */
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperleft, nextapex) > 0.0;
+ while (badedge) {
+ /* Eliminate the edge with an edge flip. As a result, the */
+ /* left triangulation will have one more boundary triangle. */
+ lnextself(nextedge);
+ sym(nextedge, topcasing);
+ lnextself(nextedge);
+ sym(nextedge, sidecasing);
+ bond(nextedge, topcasing);
+ bond(leftcand, sidecasing);
+ lnextself(leftcand);
+ sym(leftcand, outercasing);
+ lprevself(nextedge);
+ bond(nextedge, outercasing);
+ /* Correct the vertices to reflect the edge flip. */
+ setorg(leftcand, lowerleft);
+ setdest(leftcand, NULL);
+ setapex(leftcand, nextapex);
+ setorg(nextedge, NULL);
+ setdest(nextedge, upperleft);
+ setapex(nextedge, nextapex);
+ /* Consider the newly exposed vertex. */
+ upperleft = nextapex;
+ /* What vertex would be exposed if another edge were deleted? */
+ otricopy(sidecasing, nextedge);
+ apex(nextedge, nextapex);
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperleft, nextapex) > 0.0;
+ }
+ else {
+ /* Avoid eating right through the triangulation. */
+ badedge = 0;
+ }
+ }
+ }
+ }
+ /* Consider eliminating edges from the right triangulation. */
+ if (!rightfinished) {
+ /* What vertex would be exposed if an edge were deleted? */
+ lnext(rightcand, nextedge);
+ symself(nextedge);
+ apex(nextedge, nextapex);
+ /* If nextapex is NULL, then no vertex would be exposed; the */
+ /* triangulation would have been eaten right through. */
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperright, nextapex) > 0.0;
+ while (badedge) {
+ /* Eliminate the edge with an edge flip. As a result, the */
+ /* right triangulation will have one more boundary triangle. */
+ lprevself(nextedge);
+ sym(nextedge, topcasing);
+ lprevself(nextedge);
+ sym(nextedge, sidecasing);
+ bond(nextedge, topcasing);
+ bond(rightcand, sidecasing);
+ lprevself(rightcand);
+ sym(rightcand, outercasing);
+ lnextself(nextedge);
+ bond(nextedge, outercasing);
+ /* Correct the vertices to reflect the edge flip. */
+ setorg(rightcand, NULL);
+ setdest(rightcand, lowerright);
+ setapex(rightcand, nextapex);
+ setorg(nextedge, upperright);
+ setdest(nextedge, NULL);
+ setapex(nextedge, nextapex);
+ /* Consider the newly exposed vertex. */
+ upperright = nextapex;
+ /* What vertex would be exposed if another edge were deleted? */
+ otricopy(sidecasing, nextedge);
+ apex(nextedge, nextapex);
+ if (nextapex != (vertex) NULL) {
+ /* Check whether the edge is Delaunay. */
+ badedge = incircle(m, b, lowerleft, lowerright, upperright, nextapex) > 0.0;
+ }
+ else {
+ /* Avoid eating right through the triangulation. */
+ badedge = 0;
+ }
+ }
+ }
+ }
+ if (leftfinished
+ || (!rightfinished
+ && (incircle(m, b, upperleft, lowerleft, lowerright, upperright) > 0.0))) {
+ /* Knit the triangulations, adding an edge from `lowerleft' */
+ /* to `upperright'. */
+ bond(baseedge, rightcand);
+ lprev(rightcand, baseedge);
+ setdest(baseedge, lowerleft);
+ lowerright = upperright;
+ sym(baseedge, rightcand);
+ apex(rightcand, upperright);
+ }
+ else {
+ /* Knit the triangulations, adding an edge from `upperleft' */
+ /* to `lowerright'. */
+ bond(baseedge, leftcand);
+ lnext(leftcand, baseedge);
+ setorg(baseedge, lowerright);
+ lowerleft = upperleft;
+ sym(baseedge, leftcand);
+ apex(leftcand, upperleft);
+ }
+ if (b->verbose > 2) {
+ printf(" Connecting ");
+ printtriangle(m, b, &baseedge);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* divconqrecurse() Recursively form a Delaunay triangulation by the */
+/* divide-and-conquer method. */
+/* */
+/* Recursively breaks down the problem into smaller pieces, which are */
+/* knitted together by mergehulls(). The base cases (problems of two or */
+/* three vertices) are handled specially here. */
+/* */
+/* On completion, `farleft' and `farright' are bounding triangles such that */
+/* the origin of `farleft' is the leftmost vertex (breaking ties by */
+/* choosing the highest leftmost vertex), and the destination of */
+/* `farright' is the rightmost vertex (breaking ties by choosing the */
+/* lowest rightmost vertex). */
+/* */
+/*****************************************************************************/
+
+void divconqrecurse(struct mesh *m, struct behavior *b, vertex *sortarray, int vertices, int axis,
+ struct otri *farleft, struct otri *farright) {
+ struct otri midtri, tri1, tri2, tri3;
+ struct otri innerleft, innerright;
+ REAL area;
+ int divider;
+
+ if (b->verbose > 2) {
+ printf(" Triangulating %d vertices.\n", vertices);
+ }
+ if (vertices == 2) {
+ /* The triangulation of two vertices is an edge. An edge is */
+ /* represented by two bounding triangles. */
+ maketriangle(m, b, farleft);
+ setorg(*farleft, sortarray[0]);
+ setdest(*farleft, sortarray[1]);
+ /* The apex is intentionally left NULL. */
+ maketriangle(m, b, farright);
+ setorg(*farright, sortarray[1]);
+ setdest(*farright, sortarray[0]);
+ /* The apex is intentionally left NULL. */
+ bond(*farleft, *farright);
+ lprevself(*farleft);
+ lnextself(*farright);
+ bond(*farleft, *farright);
+ lprevself(*farleft);
+ lnextself(*farright);
+ bond(*farleft, *farright);
+ if (b->verbose > 2) {
+ printf(" Creating ");
+ printtriangle(m, b, farleft);
+ printf(" Creating ");
+ printtriangle(m, b, farright);
+ }
+ /* Ensure that the origin of `farleft' is sortarray[0]. */
+ lprev(*farright, *farleft);
+ return;
+ }
+ else if (vertices == 3) {
+ /* The triangulation of three vertices is either a triangle (with */
+ /* three bounding triangles) or two edges (with four bounding */
+ /* triangles). In either case, four triangles are created. */
+ maketriangle(m, b, &midtri);
+ maketriangle(m, b, &tri1);
+ maketriangle(m, b, &tri2);
+ maketriangle(m, b, &tri3);
+ area = counterclockwise(m, b, sortarray[0], sortarray[1], sortarray[2]);
+ if (area == 0.0) {
+ /* Three collinear vertices; the triangulation is two edges. */
+ setorg(midtri, sortarray[0]);
+ setdest(midtri, sortarray[1]);
+ setorg(tri1, sortarray[1]);
+ setdest(tri1, sortarray[0]);
+ setorg(tri2, sortarray[2]);
+ setdest(tri2, sortarray[1]);
+ setorg(tri3, sortarray[1]);
+ setdest(tri3, sortarray[2]);
+ /* All apices are intentionally left NULL. */
+ bond(midtri, tri1);
+ bond(tri2, tri3);
+ lnextself(midtri);
+ lprevself(tri1);
+ lnextself(tri2);
+ lprevself(tri3);
+ bond(midtri, tri3);
+ bond(tri1, tri2);
+ lnextself(midtri);
+ lprevself(tri1);
+ lnextself(tri2);
+ lprevself(tri3);
+ bond(midtri, tri1);
+ bond(tri2, tri3);
+ /* Ensure that the origin of `farleft' is sortarray[0]. */
+ otricopy(tri1, *farleft);
+ /* Ensure that the destination of `farright' is sortarray[2]. */
+ otricopy(tri2, *farright);
+ }
+ else {
+ /* The three vertices are not collinear; the triangulation is one */
+ /* triangle, namely `midtri'. */
+ setorg(midtri, sortarray[0]);
+ setdest(tri1, sortarray[0]);
+ setorg(tri3, sortarray[0]);
+ /* Apices of tri1, tri2, and tri3 are left NULL. */
+ if (area > 0.0) {
+ /* The vertices are in counterclockwise order. */
+ setdest(midtri, sortarray[1]);
+ setorg(tri1, sortarray[1]);
+ setdest(tri2, sortarray[1]);
+ setapex(midtri, sortarray[2]);
+ setorg(tri2, sortarray[2]);
+ setdest(tri3, sortarray[2]);
+ }
+ else {
+ /* The vertices are in clockwise order. */
+ setdest(midtri, sortarray[2]);
+ setorg(tri1, sortarray[2]);
+ setdest(tri2, sortarray[2]);
+ setapex(midtri, sortarray[1]);
+ setorg(tri2, sortarray[1]);
+ setdest(tri3, sortarray[1]);
+ }
+ /* The topology does not depend on how the vertices are ordered. */
+ bond(midtri, tri1);
+ lnextself(midtri);
+ bond(midtri, tri2);
+ lnextself(midtri);
+ bond(midtri, tri3);
+ lprevself(tri1);
+ lnextself(tri2);
+ bond(tri1, tri2);
+ lprevself(tri1);
+ lprevself(tri3);
+ bond(tri1, tri3);
+ lnextself(tri2);
+ lprevself(tri3);
+ bond(tri2, tri3);
+ /* Ensure that the origin of `farleft' is sortarray[0]. */
+ otricopy(tri1, *farleft);
+ /* Ensure that the destination of `farright' is sortarray[2]. */
+ if (area > 0.0) {
+ otricopy(tri2, *farright);
+ }
+ else {
+ lnext(*farleft, *farright);
+ }
+ }
+ if (b->verbose > 2) {
+ printf(" Creating ");
+ printtriangle(m, b, &midtri);
+ printf(" Creating ");
+ printtriangle(m, b, &tri1);
+ printf(" Creating ");
+ printtriangle(m, b, &tri2);
+ printf(" Creating ");
+ printtriangle(m, b, &tri3);
+ }
+ return;
+ }
+ else {
+ /* Split the vertices in half. */
+ divider = vertices >> 1;
+ /* Recursively triangulate each half. */
+ divconqrecurse(m, b, sortarray, divider, 1 - axis, farleft, &innerleft);
+ divconqrecurse(m, b, &sortarray[divider], vertices - divider, 1 - axis, &innerright,
+ farright);
+ if (b->verbose > 1) {
+ printf(" Joining triangulations with %d and %d vertices.\n", divider, vertices - divider);
+ }
+ /* Merge the two triangulations into one. */
+ mergehulls(m, b, farleft, &innerleft, &innerright, farright, axis);
+ }
+}
+
+long removeghosts(struct mesh *m, struct behavior *b, struct otri *startghost) {
+ struct otri searchedge;
+ struct otri dissolveedge;
+ struct otri deadtriangle;
+ vertex markorg;
+ long hullsize;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (b->verbose) {
+ printf(" Removing ghost triangles.\n");
+ }
+ /* Find an edge on the convex hull to start point location from. */
+ lprev(*startghost, searchedge);
+ symself(searchedge);
+ m->dummytri[0] = encode(searchedge);
+ /* Remove the bounding box and count the convex hull edges. */
+ otricopy(*startghost, dissolveedge);
+ hullsize = 0;
+ do {
+ hullsize++;
+ lnext(dissolveedge, deadtriangle);
+ lprevself(dissolveedge);
+ symself(dissolveedge);
+ /* If no PSLG is involved, set the boundary markers of all the vertices */
+ /* on the convex hull. If a PSLG is used, this step is done later. */
+ if (!b->poly) {
+ /* Watch out for the case where all the input vertices are collinear. */
+ if (dissolveedge.tri != m->dummytri) {
+ org(dissolveedge, markorg);
+ if (vertexmark(markorg) == 0) {
+ setvertexmark(markorg, 1);
+ }
+ }
+ }
+ /* Remove a bounding triangle from a convex hull triangle. */
+ dissolve(dissolveedge);
+ /* Find the next bounding triangle. */
+ sym(deadtriangle, dissolveedge);
+ /* Delete the bounding triangle. */
+ triangledealloc(m, deadtriangle.tri);
+ } while (!otriequal(dissolveedge, *startghost));
+ return hullsize;
+}
+
+/*****************************************************************************/
+/* */
+/* divconqdelaunay() Form a Delaunay triangulation by the divide-and- */
+/* conquer method. */
+/* */
+/* Sorts the vertices, calls a recursive procedure to triangulate them, and */
+/* removes the bounding box, setting boundary markers as appropriate. */
+/* */
+/*****************************************************************************/
+
+long divconqdelaunay(struct mesh *m, struct behavior *b) {
+ vertex *sortarray;
+ struct otri hullleft, hullright;
+ int divider;
+ int i, j;
+
+ if (b->verbose) {
+ printf(" Sorting vertices.\n");
+ }
+
+ /* Allocate an array of pointers to vertices for sorting. */
+ sortarray = (vertex *) trimalloc(m->invertices * (int) sizeof(vertex));
+ traversalinit(&m->vertices);
+ for (i = 0; i < m->invertices; i++) {
+ sortarray[i] = vertextraverse(m);
+ }
+ /* Sort the vertices. */
+ vertexsort(sortarray, m->invertices);
+ /* Discard duplicate vertices, which can really mess up the algorithm. */
+ i = 0;
+ for (j = 1; j < m->invertices; j++) {
+ if ((sortarray[i][0] == sortarray[j][0]) && (sortarray[i][1] == sortarray[j][1])) {
+ if (!b->quiet) {
+ printf(
+ "Warning: A duplicate vertex at (%.12g, %.12g) appeared and was ignored.\n", sortarray[j][0], sortarray[j][1]);
+ }
+ setvertextype(sortarray[j], UNDEADVERTEX);
+ m->undeads++;
+ }
+ else {
+ i++;
+ sortarray[i] = sortarray[j];
+ }
+ }
+ i++;
+ if (b->dwyer) {
+ /* Re-sort the array of vertices to accommodate alternating cuts. */
+ divider = i >> 1;
+ if (i - divider >= 2) {
+ if (divider >= 2) {
+ alternateaxes(sortarray, divider, 1);
+ }
+ alternateaxes(&sortarray[divider], i - divider, 1);
+ }
+ }
+
+ if (b->verbose) {
+ printf(" Forming triangulation.\n");
+ }
+
+ /* Form the Delaunay triangulation. */
+ divconqrecurse(m, b, sortarray, i, 0, &hullleft, &hullright);
+ trifree((VOID *) sortarray);
+
+ return removeghosts(m, b, &hullleft);
+}
+
+/** **/
+/** **/
+/********* Divide-and-conquer Delaunay triangulation ends here *********/
+
+/********* General mesh construction routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* delaunay() Form a Delaunay triangulation. */
+/* */
+/*****************************************************************************/
+
+long delaunay(struct mesh *m, struct behavior *b) {
+ long hulledges;
+
+ m->eextras = 0;
+ initializetrisubpools(m, b);
+
+#ifdef REDUCED
+ if (!b->quiet) {
+ printf( "Constructing Delaunay triangulation by divide-and-conquer method.\n");
+ }
+ hulledges = divconqdelaunay(m, b);
+#else /* not REDUCED */
+ if (!b->quiet)
+ {
+ printf("Constructing Delaunay triangulation ");
+ if (b->incremental)
+ {
+ printf("by incremental method.\n");
+ }
+ else if (b->sweepline)
+ {
+ printf("by sweepline method.\n");
+ }
+ else
+ {
+ printf("by divide-and-conquer method.\n");
+ }
+ }
+ if (b->incremental)
+ {
+ hulledges = incrementaldelaunay(m, b);
+ }
+ else if (b->sweepline)
+ {
+ hulledges = sweeplinedelaunay(m, b);
+ }
+ else
+ {
+ hulledges = divconqdelaunay(m, b);
+ }
+#endif /* not REDUCED */
+
+ if (m->triangles.items == 0) {
+ /* The input vertices were all collinear, so there are no triangles. */
+ return 0l;
+ }
+ else {
+ return hulledges;
+ }
+}
+
+/** **/
+/** **/
+/********* General mesh construction routines end here *********/
+
+/********* Segment insertion begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* finddirection() Find the first triangle on the path from one point */
+/* to another. */
+/* */
+/* Finds the triangle that intersects a line segment drawn from the */
+/* origin of `searchtri' to the point `searchpoint', and returns the result */
+/* in `searchtri'. The origin of `searchtri' does not change, even though */
+/* the triangle returned may differ from the one passed in. This routine */
+/* is used to find the direction to move in to get from one point to */
+/* another. */
+/* */
+/* The return value notes whether the destination or apex of the found */
+/* triangle is collinear with the two points in question. */
+/* */
+/*****************************************************************************/
+
+enum finddirectionresult finddirection(struct mesh *m, struct behavior *b, struct otri *searchtri,
+ vertex searchpoint) {
+ struct otri checktri;
+ vertex startvertex;
+ vertex leftvertex, rightvertex;
+ REAL leftccw, rightccw;
+ int leftflag, rightflag;
+ triangle ptr; /* Temporary variable used by onext() and oprev(). */
+
+ org(*searchtri, startvertex);
+ dest(*searchtri, rightvertex);
+ apex(*searchtri, leftvertex);
+ /* Is `searchpoint' to the left? */
+ leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex);
+ leftflag = leftccw > 0.0;
+ /* Is `searchpoint' to the right? */
+ rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex);
+ rightflag = rightccw > 0.0;
+ if (leftflag && rightflag) {
+ /* `searchtri' faces directly away from `searchpoint'. We could go left */
+ /* or right. Ask whether it's a triangle or a boundary on the left. */
+ onext(*searchtri, checktri);
+ if (checktri.tri == m->dummytri) {
+ leftflag = 0;
+ }
+ else {
+ rightflag = 0;
+ }
+ }
+ while (leftflag) {
+ /* Turn left until satisfied. */
+ onextself(*searchtri);
+ if (searchtri->tri == m->dummytri) {
+ printf("Internal error in finddirection(): Unable to find a\n");
+ printf(" triangle leading from (%.12g, %.12g) to", startvertex[0], startvertex[1]);
+ printf(" (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ internalerror();
+ }
+ apex(*searchtri, leftvertex);
+ rightccw = leftccw;
+ leftccw = counterclockwise(m, b, searchpoint, startvertex, leftvertex);
+ leftflag = leftccw > 0.0;
+ }
+ while (rightflag) {
+ /* Turn right until satisfied. */
+ oprevself(*searchtri);
+ if (searchtri->tri == m->dummytri) {
+ printf("Internal error in finddirection(): Unable to find a\n");
+ printf(" triangle leading from (%.12g, %.12g) to", startvertex[0], startvertex[1]);
+ printf(" (%.12g, %.12g).\n", searchpoint[0], searchpoint[1]);
+ internalerror();
+ }
+ dest(*searchtri, rightvertex);
+ leftccw = rightccw;
+ rightccw = counterclockwise(m, b, startvertex, searchpoint, rightvertex);
+ rightflag = rightccw > 0.0;
+ }
+ if (leftccw == 0.0) {
+ return LEFTCOLLINEAR;
+ }
+ else if (rightccw == 0.0) {
+ return RIGHTCOLLINEAR;
+ }
+ else {
+ return WITHIN;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* segmentintersection() Find the intersection of an existing segment */
+/* and a segment that is being inserted. Insert */
+/* a vertex at the intersection, splitting an */
+/* existing subsegment. */
+/* */
+/* The segment being inserted connects the apex of splittri to endpoint2. */
+/* splitsubseg is the subsegment being split, and MUST adjoin splittri. */
+/* Hence, endpoints of the subsegment being split are the origin and */
+/* destination of splittri. */
+/* */
+/* On completion, splittri is a handle having the newly inserted */
+/* intersection point as its origin, and endpoint1 as its destination. */
+/* */
+/*****************************************************************************/
+
+void segmentintersection(struct mesh *m, struct behavior *b, struct otri *splittri,
+ struct osub *splitsubseg, vertex endpoint2) {
+ struct osub opposubseg;
+ vertex endpoint1;
+ vertex torg, tdest;
+ vertex leftvertex, rightvertex;
+ vertex newvertex;
+ enum insertvertexresult success;
+ //enum finddirectionresult collinear;
+ REAL ex, ey;
+ REAL tx, ty;
+ REAL etx, ety;
+ REAL split, denom;
+ int i;
+ triangle ptr; /* Temporary variable used by onext(). */
+ subseg sptr; /* Temporary variable used by snext(). */
+
+ /* Find the other three segment endpoints. */
+ apex(*splittri, endpoint1);
+ org(*splittri, torg);
+ dest(*splittri, tdest);
+ /* Segment intersection formulae; see the Antonio reference. */
+ tx = tdest[0] - torg[0];
+ ty = tdest[1] - torg[1];
+ ex = endpoint2[0] - endpoint1[0];
+ ey = endpoint2[1] - endpoint1[1];
+ etx = torg[0] - endpoint2[0];
+ ety = torg[1] - endpoint2[1];
+ denom = ty * ex - tx * ey;
+ if (denom == 0.0) {
+ printf("Internal error in segmentintersection():");
+ printf(" Attempt to find intersection of parallel segments.\n");
+ internalerror();
+ return;
+ }
+ split = (ey * etx - ex * ety) / denom;
+ /* Create the new vertex. */
+ newvertex = (vertex) poolalloc(&m->vertices);
+ /* Interpolate its coordinate and attributes. */
+ for (i = 0; i < 2 + m->nextras; i++) {
+ newvertex[i] = torg[i] + split * (tdest[i] - torg[i]);
+ }
+ setvertexmark(newvertex, mark(*splitsubseg));
+ setvertextype(newvertex, INPUTVERTEX);
+ if (b->verbose > 1) {
+ printf(
+ " Splitting subsegment (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", torg[0], torg[1], tdest[0], tdest[1], newvertex[0], newvertex[1]);
+ }
+ /* Insert the intersection vertex. This should always succeed. */
+ success = insertvertex(m, b, newvertex, splittri, splitsubseg, 0, 0);
+ if (success != SUCCESSFULVERTEX) {
+ printf("Internal error in segmentintersection():\n");
+ printf(" Failure to split a segment.\n");
+ internalerror();
+ return;
+ }
+ /* Record a triangle whose origin is the new vertex. */
+ setvertex2tri(newvertex, encode(*splittri));
+ if (m->steinerleft > 0) {
+ m->steinerleft--;
+ }
+
+ /* Divide the segment into two, and correct the segment endpoints. */
+ ssymself(*splitsubseg);
+ spivot(*splitsubseg, opposubseg);
+ sdissolve(*splitsubseg);
+ sdissolve(opposubseg);
+ do {
+ setsegorg(*splitsubseg, newvertex);
+ snextself(*splitsubseg);
+ } while (splitsubseg->ss != m->dummysub);
+ do {
+ setsegorg(opposubseg, newvertex);
+ snextself(opposubseg);
+ } while (opposubseg.ss != m->dummysub);
+
+ /* Inserting the vertex may have caused edge flips. We wish to rediscover */
+ /* the edge connecting endpoint1 to the new intersection vertex. */
+
+ // FIXME collinear =
+ finddirection(m, b, splittri, endpoint1);
+
+ dest(*splittri, rightvertex);
+ apex(*splittri, leftvertex);
+ if ((leftvertex[0] == endpoint1[0]) && (leftvertex[1] == endpoint1[1])) {
+ onextself(*splittri);
+ }
+ else if ((rightvertex[0] != endpoint1[0]) || (rightvertex[1] != endpoint1[1])) {
+ printf("Internal error in segmentintersection():\n");
+ printf(" Topological inconsistency after splitting a segment.\n");
+ internalerror();
+ return;
+ }
+ /* `splittri' should have destination endpoint1. */
+}
+
+/*****************************************************************************/
+/* */
+/* scoutsegment() Scout the first triangle on the path from one endpoint */
+/* to another, and check for completion (reaching the */
+/* second endpoint), a collinear vertex, or the */
+/* intersection of two segments. */
+/* */
+/* Returns one if the entire segment is successfully inserted, and zero if */
+/* the job must be finished by conformingedge() or constrainededge(). */
+/* */
+/* If the first triangle on the path has the second endpoint as its */
+/* destination or apex, a subsegment is inserted and the job is done. */
+/* */
+/* If the first triangle on the path has a destination or apex that lies on */
+/* the segment, a subsegment is inserted connecting the first endpoint to */
+/* the collinear vertex, and the search is continued from the collinear */
+/* vertex. */
+/* */
+/* If the first triangle on the path has a subsegment opposite its origin, */
+/* then there is a segment that intersects the segment being inserted. */
+/* Their intersection vertex is inserted, splitting the subsegment. */
+/* */
+/*****************************************************************************/
+
+int scoutsegment(struct mesh *m, struct behavior *b, struct otri *searchtri, vertex endpoint2,
+ int newmark) {
+ struct otri crosstri;
+ struct osub crosssubseg;
+ vertex leftvertex, rightvertex;
+ enum finddirectionresult collinear;
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ collinear = finddirection(m, b, searchtri, endpoint2);
+ dest(*searchtri, rightvertex);
+ apex(*searchtri, leftvertex);
+ if (((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1]))
+ || ((rightvertex[0] == endpoint2[0]) && (rightvertex[1] == endpoint2[1]))) {
+ /* The segment is already an edge in the mesh. */
+ if ((leftvertex[0] == endpoint2[0]) && (leftvertex[1] == endpoint2[1])) {
+ lprevself(*searchtri);
+ }
+ /* Insert a subsegment, if there isn't already one there. */
+ insertsubseg(m, b, searchtri, newmark);
+ return 1;
+ }
+ else if (collinear == LEFTCOLLINEAR) {
+ /* We've collided with a vertex between the segment's endpoints. */
+ /* Make the collinear vertex be the triangle's origin. */
+ lprevself(*searchtri);
+ insertsubseg(m, b, searchtri, newmark);
+ /* Insert the remainder of the segment. */
+ return scoutsegment(m, b, searchtri, endpoint2, newmark);
+ }
+ else if (collinear == RIGHTCOLLINEAR) {
+ /* We've collided with a vertex between the segment's endpoints. */
+ insertsubseg(m, b, searchtri, newmark);
+ /* Make the collinear vertex be the triangle's origin. */
+ lnextself(*searchtri);
+ /* Insert the remainder of the segment. */
+ return scoutsegment(m, b, searchtri, endpoint2, newmark);
+ }
+ else {
+ lnext(*searchtri, crosstri);
+ tspivot(crosstri, crosssubseg);
+ /* Check for a crossing segment. */
+ if (crosssubseg.ss == m->dummysub) {
+ return 0;
+ }
+ else {
+ /* Insert a vertex at the intersection. */
+ segmentintersection(m, b, &crosstri, &crosssubseg, endpoint2);
+ if (error_set)
+ return -1;
+ otricopy(crosstri, *searchtri);
+ insertsubseg(m, b, searchtri, newmark);
+ /* Insert the remainder of the segment. */
+ return scoutsegment(m, b, searchtri, endpoint2, newmark);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* delaunayfixup() Enforce the Delaunay condition at an edge, fanning out */
+/* recursively from an existing vertex. Pay special */
+/* attention to stacking inverted triangles. */
+/* */
+/* This is a support routine for inserting segments into a constrained */
+/* Delaunay triangulation. */
+/* */
+/* The origin of fixuptri is treated as if it has just been inserted, and */
+/* the local Delaunay condition needs to be enforced. It is only enforced */
+/* in one sector, however, that being the angular range defined by */
+/* fixuptri. */
+/* */
+/* This routine also needs to make decisions regarding the "stacking" of */
+/* triangles. (Read the description of constrainededge() below before */
+/* reading on here, so you understand the algorithm.) If the position of */
+/* the new vertex (the origin of fixuptri) indicates that the vertex before */
+/* it on the polygon is a reflex vertex, then "stack" the triangle by */
+/* doing nothing. (fixuptri is an inverted triangle, which is how stacked */
+/* triangles are identified.) */
+/* */
+/* Otherwise, check whether the vertex before that was a reflex vertex. */
+/* If so, perform an edge flip, thereby eliminating an inverted triangle */
+/* (popping it off the stack). The edge flip may result in the creation */
+/* of a new inverted triangle, depending on whether or not the new vertex */
+/* is visible to the vertex three edges behind on the polygon. */
+/* */
+/* If neither of the two vertices behind the new vertex are reflex */
+/* vertices, fixuptri and fartri, the triangle opposite it, are not */
+/* inverted; hence, ensure that the edge between them is locally Delaunay. */
+/* */
+/* `leftside' indicates whether or not fixuptri is to the left of the */
+/* segment being inserted. (Imagine that the segment is pointing up from */
+/* endpoint1 to endpoint2.) */
+/* */
+/*****************************************************************************/
+
+void delaunayfixup(struct mesh *m, struct behavior *b, struct otri *fixuptri, int leftside) {
+ struct otri neartri;
+ struct otri fartri;
+ struct osub faredge;
+ vertex nearvertex, leftvertex, rightvertex, farvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ lnext(*fixuptri, neartri);
+ sym(neartri, fartri);
+ /* Check if the edge opposite the origin of fixuptri can be flipped. */
+ if (fartri.tri == m->dummytri) {
+ return;
+ }
+ tspivot(neartri, faredge);
+ if (faredge.ss != m->dummysub) {
+ return;
+ }
+ /* Find all the relevant vertices. */
+ apex(neartri, nearvertex);
+ org(neartri, leftvertex);
+ dest(neartri, rightvertex);
+ apex(fartri, farvertex);
+ /* Check whether the previous polygon vertex is a reflex vertex. */
+ if (leftside) {
+ if (counterclockwise(m, b, nearvertex, leftvertex, farvertex) <= 0.0) {
+ /* leftvertex is a reflex vertex too. Nothing can */
+ /* be done until a convex section is found. */
+ return;
+ }
+ }
+ else {
+ if (counterclockwise(m, b, farvertex, rightvertex, nearvertex) <= 0.0) {
+ /* rightvertex is a reflex vertex too. Nothing can */
+ /* be done until a convex section is found. */
+ return;
+ }
+ }
+ if (counterclockwise(m, b, rightvertex, leftvertex, farvertex) > 0.0) {
+ /* fartri is not an inverted triangle, and farvertex is not a reflex */
+ /* vertex. As there are no reflex vertices, fixuptri isn't an */
+ /* inverted triangle, either. Hence, test the edge between the */
+ /* triangles to ensure it is locally Delaunay. */
+ if (incircle(m, b, leftvertex, farvertex, rightvertex, nearvertex) <= 0.0) {
+ return;
+ }
+ /* Not locally Delaunay; go on to an edge flip. */
+ } /* else fartri is inverted; remove it from the stack by flipping. */
+ flip(m, b, &neartri);
+ lprevself(*fixuptri);
+ /* Restore the origin of fixuptri after the flip. */
+ /* Recursively process the two triangles that result from the flip. */
+ delaunayfixup(m, b, fixuptri, leftside);
+ delaunayfixup(m, b, &fartri, leftside);
+}
+
+/*****************************************************************************/
+/* */
+/* constrainededge() Force a segment into a constrained Delaunay */
+/* triangulation by deleting the triangles it */
+/* intersects, and triangulating the polygons that */
+/* form on each side of it. */
+/* */
+/* Generates a single subsegment connecting `endpoint1' to `endpoint2'. */
+/* The triangle `starttri' has `endpoint1' as its origin. `newmark' is the */
+/* boundary marker of the segment. */
+/* */
+/* To insert a segment, every triangle whose interior intersects the */
+/* segment is deleted. The union of these deleted triangles is a polygon */
+/* (which is not necessarily monotone, but is close enough), which is */
+/* divided into two polygons by the new segment. This routine's task is */
+/* to generate the Delaunay triangulation of these two polygons. */
+/* */
+/* You might think of this routine's behavior as a two-step process. The */
+/* first step is to walk from endpoint1 to endpoint2, flipping each edge */
+/* encountered. This step creates a fan of edges connected to endpoint1, */
+/* including the desired edge to endpoint2. The second step enforces the */
+/* Delaunay condition on each side of the segment in an incremental manner: */
+/* proceeding along the polygon from endpoint1 to endpoint2 (this is done */
+/* independently on each side of the segment), each vertex is "enforced" */
+/* as if it had just been inserted, but affecting only the previous */
+/* vertices. The result is the same as if the vertices had been inserted */
+/* in the order they appear on the polygon, so the result is Delaunay. */
+/* */
+/* In truth, constrainededge() interleaves these two steps. The procedure */
+/* walks from endpoint1 to endpoint2, and each time an edge is encountered */
+/* and flipped, the newly exposed vertex (at the far end of the flipped */
+/* edge) is "enforced" upon the previously flipped edges, usually affecting */
+/* only one side of the polygon (depending upon which side of the segment */
+/* the vertex falls on). */
+/* */
+/* The algorithm is complicated by the need to handle polygons that are not */
+/* convex. Although the polygon is not necessarily monotone, it can be */
+/* triangulated in a manner similar to the stack-based algorithms for */
+/* monotone polygons. For each reflex vertex (local concavity) of the */
+/* polygon, there will be an inverted triangle formed by one of the edge */
+/* flips. (An inverted triangle is one with negative area - that is, its */
+/* vertices are arranged in clockwise order - and is best thought of as a */
+/* wrinkle in the fabric of the mesh.) Each inverted triangle can be */
+/* thought of as a reflex vertex pushed on the stack, waiting to be fixed */
+/* later. */
+/* */
+/* A reflex vertex is popped from the stack when a vertex is inserted that */
+/* is visible to the reflex vertex. (However, if the vertex behind the */
+/* reflex vertex is not visible to the reflex vertex, a new inverted */
+/* triangle will take its place on the stack.) These details are handled */
+/* by the delaunayfixup() routine above. */
+/* */
+/*****************************************************************************/
+
+void constrainededge(struct mesh *m, struct behavior *b, struct otri *starttri, vertex endpoint2,
+ int newmark) {
+ struct otri fixuptri, fixuptri2;
+ struct osub crosssubseg;
+ vertex endpoint1;
+ vertex farvertex;
+ REAL area;
+ int collision;
+ int done;
+ triangle ptr; /* Temporary variable used by sym() and oprev(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ org(*starttri, endpoint1);
+ lnext(*starttri, fixuptri);
+ flip(m, b, &fixuptri);
+ /* `collision' indicates whether we have found a vertex directly */
+ /* between endpoint1 and endpoint2. */
+ collision = 0;
+ done = 0;
+ do {
+ org(fixuptri, farvertex);
+ /* `farvertex' is the extreme point of the polygon we are "digging" */
+ /* to get from endpoint1 to endpoint2. */
+ if ((farvertex[0] == endpoint2[0]) && (farvertex[1] == endpoint2[1])) {
+ oprev(fixuptri, fixuptri2);
+ /* Enforce the Delaunay condition around endpoint2. */
+ delaunayfixup(m, b, &fixuptri, 0);
+ delaunayfixup(m, b, &fixuptri2, 1);
+ done = 1;
+ }
+ else {
+ /* Check whether farvertex is to the left or right of the segment */
+ /* being inserted, to decide which edge of fixuptri to dig */
+ /* through next. */
+ area = counterclockwise(m, b, endpoint1, endpoint2, farvertex);
+ if (area == 0.0) {
+ /* We've collided with a vertex between endpoint1 and endpoint2. */
+ collision = 1;
+ oprev(fixuptri, fixuptri2);
+ /* Enforce the Delaunay condition around farvertex. */
+ delaunayfixup(m, b, &fixuptri, 0);
+ delaunayfixup(m, b, &fixuptri2, 1);
+ done = 1;
+ }
+ else {
+ if (area > 0.0) { /* farvertex is to the left of the segment. */
+ oprev(fixuptri, fixuptri2);
+ /* Enforce the Delaunay condition around farvertex, on the */
+ /* left side of the segment only. */
+ delaunayfixup(m, b, &fixuptri2, 1);
+ /* Flip the edge that crosses the segment. After the edge is */
+ /* flipped, one of its endpoints is the fan vertex, and the */
+ /* destination of fixuptri is the fan vertex. */
+ lprevself(fixuptri);
+ }
+ else { /* farvertex is to the right of the segment. */
+ delaunayfixup(m, b, &fixuptri, 0);
+ /* Flip the edge that crosses the segment. After the edge is */
+ /* flipped, one of its endpoints is the fan vertex, and the */
+ /* destination of fixuptri is the fan vertex. */
+ oprevself(fixuptri);
+ }
+ /* Check for two intersecting segments. */
+ tspivot(fixuptri, crosssubseg);
+ if (crosssubseg.ss == m->dummysub) {
+ flip(m, b, &fixuptri); /* May create inverted triangle at left. */
+ }
+ else {
+ /* We've collided with a segment between endpoint1 and endpoint2. */
+ collision = 1;
+ /* Insert a vertex at the intersection. */
+ segmentintersection(m, b, &fixuptri, &crosssubseg, endpoint2);
+ done = 1;
+ }
+ }
+ }
+ } while (!done);
+ /* Insert a subsegment to make the segment permanent. */
+ insertsubseg(m, b, &fixuptri, newmark);
+ /* If there was a collision with an interceding vertex, install another */
+ /* segment connecting that vertex with endpoint2. */
+ if (collision) {
+ /* Insert the remainder of the segment. */
+ if (!scoutsegment(m, b, &fixuptri, endpoint2, newmark)) {
+ constrainededge(m, b, &fixuptri, endpoint2, newmark);
+ }
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* insertsegment() Insert a PSLG segment into a triangulation. */
+/* */
+/*****************************************************************************/
+
+void insertsegment(struct mesh *m, struct behavior *b, vertex endpoint1, vertex endpoint2,
+ int newmark) {
+ struct otri searchtri1, searchtri2;
+ triangle encodedtri;
+ vertex checkvertex;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (b->verbose > 1) {
+ printf( " Connecting (%.12g, %.12g) to (%.12g, %.12g).\n",
+ endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]);
+ }
+
+ /* Find a triangle whose origin is the segment's first endpoint. */
+ checkvertex = (vertex) NULL;
+ encodedtri = vertex2tri(endpoint1);
+ if (encodedtri != (triangle) NULL) {
+ decode(encodedtri, searchtri1);
+ org(searchtri1, checkvertex);
+ }
+ if (checkvertex != endpoint1) {
+ /* Find a boundary triangle to search from. */
+ searchtri1.tri = m->dummytri;
+ searchtri1.orient = 0;
+ symself(searchtri1);
+ /* Search for the segment's first endpoint by point location. */
+ if (locate(m, b, endpoint1, &searchtri1) != ONVERTEX) {
+ printf( "Internal error in insertsegment(): Unable to locate PSLG vertex\n");
+ printf(" (%.12g, %.12g) in triangulation.\n", endpoint1[0], endpoint1[1]);
+ internalerror();
+ }
+ }
+ /* Remember this triangle to improve subsequent point location. */
+ otricopy(searchtri1, m->recenttri);
+ /* Scout the beginnings of a path from the first endpoint */
+ /* toward the second. */
+ if (scoutsegment(m, b, &searchtri1, endpoint2, newmark)) {
+ /* The segment was easily inserted. */
+ return;
+ }
+ /* The first endpoint may have changed if a collision with an intervening */
+ /* vertex on the segment occurred. */
+ org(searchtri1, endpoint1);
+
+ /* Find a triangle whose origin is the segment's second endpoint. */
+ checkvertex = (vertex) NULL;
+ encodedtri = vertex2tri(endpoint2);
+ if (encodedtri != (triangle) NULL) {
+ decode(encodedtri, searchtri2);
+ org(searchtri2, checkvertex);
+ }
+ if (checkvertex != endpoint2) {
+ /* Find a boundary triangle to search from. */
+ searchtri2.tri = m->dummytri;
+ searchtri2.orient = 0;
+ symself(searchtri2);
+ /* Search for the segment's second endpoint by point location. */
+ if (locate(m, b, endpoint2, &searchtri2) != ONVERTEX) {
+ printf( "Internal error in insertsegment(): Unable to locate PSLG vertex\n");
+ printf(" (%.12g, %.12g) in triangulation.\n", endpoint2[0], endpoint2[1]);
+ internalerror();
+ }
+ }
+ /* Remember this triangle to improve subsequent point location. */
+ otricopy(searchtri2, m->recenttri);
+ /* Scout the beginnings of a path from the second endpoint */
+ /* toward the first. */
+ if (scoutsegment(m, b, &searchtri2, endpoint1, newmark)) {
+ /* The segment was easily inserted. */
+ return;
+ }
+ /* The second endpoint may have changed if a collision with an intervening */
+ /* vertex on the segment occurred. */
+ org(searchtri2, endpoint2);
+
+#ifndef REDUCED
+#ifndef CDT_ONLY
+ if (b->splitseg)
+ {
+ /* Insert vertices to force the segment into the triangulation. */
+ conformingedge(m, b, endpoint1, endpoint2, newmark);
+ }
+ else
+ {
+#endif /* not CDT_ONLY */
+#endif /* not REDUCED */
+ /* Insert the segment directly into the triangulation. */
+ constrainededge(m, b, &searchtri1, endpoint2, newmark);
+#ifndef REDUCED
+#ifndef CDT_ONLY
+}
+#endif /* not CDT_ONLY */
+#endif /* not REDUCED */
+}
+
+/*****************************************************************************/
+/* */
+/* markhull() Cover the convex hull of a triangulation with subsegments. */
+/* */
+/*****************************************************************************/
+
+void markhull(struct mesh *m, struct behavior *b) {
+ struct otri hulltri;
+ struct otri nexttri;
+ struct otri starttri;
+ triangle ptr; /* Temporary variable used by sym() and oprev(). */
+
+ /* Find a triangle handle on the hull. */
+ hulltri.tri = m->dummytri;
+ hulltri.orient = 0;
+ symself(hulltri);
+ /* Remember where we started so we know when to stop. */
+ otricopy(hulltri, starttri);
+ /* Go once counterclockwise around the convex hull. */
+ do {
+ /* Create a subsegment if there isn't already one here. */
+ insertsubseg(m, b, &hulltri, 1);
+ /* To find the next hull edge, go clockwise around the next vertex. */
+ lnextself(hulltri);
+ oprev(hulltri, nexttri);
+ while (nexttri.tri != m->dummytri) {
+ otricopy(nexttri, hulltri);
+ oprev(hulltri, nexttri);
+ }
+ } while (!otriequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/* */
+/* formskeleton() Create the segments of a triangulation, including PSLG */
+/* segments and edges on the convex hull. */
+/* */
+/* The PSLG segments are read from a .poly file. The return value is the */
+/* number of segments in the file. */
+/* */
+/*****************************************************************************/
+
+void formskeleton(struct mesh *m, struct behavior *b, int *segmentlist, int *segmentmarkerlist,
+ int numberofsegments) {
+ char polyfilename[6];
+ int index;
+ vertex endpoint1, endpoint2;
+ int segmentmarkers;
+ int end1, end2;
+ int boundmarker;
+ int i;
+
+ if (b->poly) {
+ if (!b->quiet) {
+ printf("Recovering segments in Delaunay triangulation.\n");
+ }
+ strcpy(polyfilename, "input");
+ m->insegments = numberofsegments;
+ segmentmarkers = segmentmarkerlist != (int *) NULL;
+ index = 0;
+ /* If the input vertices are collinear, there is no triangulation, */
+ /* so don't try to insert segments. */
+ if (m->triangles.items == 0) {
+ return;
+ }
+
+ /* If segments are to be inserted, compute a mapping */
+ /* from vertices to triangles. */
+ if (m->insegments > 0) {
+ makevertexmap(m, b);
+ if (b->verbose) {
+ printf(" Recovering PSLG segments.\n");
+ }
+ }
+
+ boundmarker = 0;
+ /* Read and insert the segments. */
+ for (i = 0; i < m->insegments; i++) {
+ end1 = segmentlist[index++];
+ end2 = segmentlist[index++];
+ if (segmentmarkers) {
+ boundmarker = segmentmarkerlist[i];
+ }
+ if ((end1 < b->firstnumber) || (end1 >= b->firstnumber + m->invertices)) {
+ if (!b->quiet) {
+ printf( "Warning: Invalid first endpoint of segment %d in %s.\n",
+ b->firstnumber + i, polyfilename);
+ }
+ }
+ else if ((end2 < b->firstnumber) || (end2 >= b->firstnumber + m->invertices)) {
+ if (!b->quiet) {
+ printf( "Warning: Invalid second endpoint of segment %d in %s.\n",
+ b->firstnumber + i, polyfilename);
+ }
+ }
+ else {
+ /* Find the vertices numbered `end1' and `end2'. */
+ endpoint1 = getvertex(m, b, end1);
+ endpoint2 = getvertex(m, b, end2);
+ if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) {
+ if (!b->quiet) {
+ printf( "Warning: Endpoints of segment %d are coincident in %s.\n",
+ b->firstnumber + i, polyfilename);
+ }
+ }
+ else {
+ insertsegment(m, b, endpoint1, endpoint2, boundmarker);
+ }
+ }
+ }
+ }
+ else {
+ m->insegments = 0;
+ }
+ if (b->convex || !b->poly) {
+ /* Enclose the convex hull with subsegments. */
+ if (b->verbose) {
+ printf(" Enclosing convex hull with segments.\n");
+ }
+ markhull(m, b);
+ }
+}
+
+/** **/
+/** **/
+/********* Segment insertion ends here *********/
+
+/********* Carving out holes and concavities begins here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* infecthull() Virally infect all of the triangles of the convex hull */
+/* that are not protected by subsegments. Where there are */
+/* subsegments, set boundary markers as appropriate. */
+/* */
+/*****************************************************************************/
+
+void infecthull(struct mesh *m, struct behavior *b) {
+ struct otri hulltri;
+ struct otri nexttri;
+ struct otri starttri;
+ struct osub hullsubseg;
+ triangle **deadtriangle;
+ vertex horg, hdest;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose) {
+ printf(" Marking concavities (external triangles) for elimination.\n");
+ }
+ /* Find a triangle handle on the hull. */
+ hulltri.tri = m->dummytri;
+ hulltri.orient = 0;
+ symself(hulltri);
+ /* Remember where we started so we know when to stop. */
+ otricopy(hulltri, starttri);
+ /* Go once counterclockwise around the convex hull. */
+ do {
+ /* Ignore triangles that are already infected. */
+ if (!infected(hulltri)) {
+ /* Is the triangle protected by a subsegment? */
+ tspivot(hulltri, hullsubseg);
+ if (hullsubseg.ss == m->dummysub) {
+ /* The triangle is not protected; infect it. */
+ if (!infected(hulltri)) {
+ infect(hulltri);
+ deadtriangle = (triangle **) poolalloc(&m->viri);
+ *deadtriangle = hulltri.tri;
+ }
+ }
+ else {
+ /* The triangle is protected; set boundary markers if appropriate. */
+ if (mark(hullsubseg) == 0) {
+ setmark(hullsubseg, 1);
+ org(hulltri, horg);
+ dest(hulltri, hdest);
+ if (vertexmark(horg) == 0) {
+ setvertexmark(horg, 1);
+ }
+ if (vertexmark(hdest) == 0) {
+ setvertexmark(hdest, 1);
+ }
+ }
+ }
+ }
+ /* To find the next hull edge, go clockwise around the next vertex. */
+ lnextself(hulltri);
+ oprev(hulltri, nexttri);
+ while (nexttri.tri != m->dummytri) {
+ otricopy(nexttri, hulltri);
+ oprev(hulltri, nexttri);
+ }
+ } while (!otriequal(hulltri, starttri));
+}
+
+/*****************************************************************************/
+/* */
+/* plague() Spread the virus from all infected triangles to any neighbors */
+/* not protected by subsegments. Delete all infected triangles. */
+/* */
+/* This is the procedure that actually creates holes and concavities. */
+/* */
+/* This procedure operates in two phases. The first phase identifies all */
+/* the triangles that will die, and marks them as infected. They are */
+/* marked to ensure that each triangle is added to the virus pool only */
+/* once, so the procedure will terminate. */
+/* */
+/* The second phase actually eliminates the infected triangles. It also */
+/* eliminates orphaned vertices. */
+/* */
+/*****************************************************************************/
+
+void plague(struct mesh *m, struct behavior *b) {
+ struct otri testtri;
+ struct otri neighbor;
+ triangle **virusloop;
+ triangle **deadtriangle;
+ struct osub neighborsubseg;
+ vertex testvertex;
+ vertex norg, ndest;
+ vertex deadorg, deaddest, deadapex;
+ int killorg;
+ triangle ptr; /* Temporary variable used by sym() and onext(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose) {
+ printf(" Marking neighbors of marked triangles.\n");
+ }
+ /* Loop through all the infected triangles, spreading the virus to */
+ /* their neighbors, then to their neighbors' neighbors. */
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+ /* A triangle is marked as infected by messing with one of its pointers */
+ /* to subsegments, setting it to an illegal value. Hence, we have to */
+ /* temporarily uninfect this triangle so that we can examine its */
+ /* adjacent subsegments. */
+ uninfect(testtri);
+ if (b->verbose > 2) {
+ /* Assign the triangle an orientation for convenience in */
+ /* checking its vertices. */
+ testtri.orient = 0;
+ org(testtri, deadorg);
+ dest(testtri, deaddest);
+ apex(testtri, deadapex);
+ printf(
+ " Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", deadorg[0], deadorg[1], deaddest[0], deaddest[1], deadapex[0], deadapex[1]);
+ }
+ /* Check each of the triangle's three neighbors. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ /* Find the neighbor. */
+ sym(testtri, neighbor);
+ /* Check for a subsegment between the triangle and its neighbor. */
+ tspivot(testtri, neighborsubseg);
+ /* Check if the neighbor is nonexistent or already infected. */
+ if ((neighbor.tri == m->dummytri) || infected(neighbor)) {
+ if (neighborsubseg.ss != m->dummysub) {
+ /* There is a subsegment separating the triangle from its */
+ /* neighbor, but both triangles are dying, so the subsegment */
+ /* dies too. */
+ subsegdealloc(m, neighborsubseg.ss);
+ if (neighbor.tri != m->dummytri) {
+ /* Make sure the subsegment doesn't get deallocated again */
+ /* later when the infected neighbor is visited. */
+ uninfect(neighbor);
+ tsdissolve(neighbor);
+ infect(neighbor);
+ }
+ }
+ }
+ else { /* The neighbor exists and is not infected. */
+ if (neighborsubseg.ss == m->dummysub) {
+ /* There is no subsegment protecting the neighbor, so */
+ /* the neighbor becomes infected. */
+ if (b->verbose > 2) {
+ org(neighbor, deadorg);
+ dest(neighbor, deaddest);
+ apex(neighbor, deadapex);
+ printf(
+ " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", deadorg[0], deadorg[1], deaddest[0], deaddest[1], deadapex[0], deadapex[1]);
+ }
+ infect(neighbor);
+ /* Ensure that the neighbor's neighbors will be infected. */
+ deadtriangle = (triangle **) poolalloc(&m->viri);
+ *deadtriangle = neighbor.tri;
+ }
+ else { /* The neighbor is protected by a subsegment. */
+ /* Remove this triangle from the subsegment. */
+ stdissolve(neighborsubseg);
+ /* The subsegment becomes a boundary. Set markers accordingly. */
+ if (mark(neighborsubseg) == 0) {
+ setmark(neighborsubseg, 1);
+ }
+ org(neighbor, norg);
+ dest(neighbor, ndest);
+ if (vertexmark(norg) == 0) {
+ setvertexmark(norg, 1);
+ }
+ if (vertexmark(ndest) == 0) {
+ setvertexmark(ndest, 1);
+ }
+ }
+ }
+ }
+ /* Remark the triangle as infected, so it doesn't get added to the */
+ /* virus pool again. */
+ infect(testtri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+
+ if (b->verbose) {
+ printf(" Deleting marked triangles.\n");
+ }
+
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+
+ /* Check each of the three corners of the triangle for elimination. */
+ /* This is done by walking around each vertex, checking if it is */
+ /* still connected to at least one live triangle. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ org(testtri, testvertex);
+ /* Check if the vertex has already been tested. */
+ if (testvertex != (vertex) NULL) {
+ killorg = 1;
+ /* Mark the corner of the triangle as having been tested. */
+ setorg(testtri, NULL);
+ /* Walk counterclockwise about the vertex. */
+ onext(testtri, neighbor);
+ /* Stop upon reaching a boundary or the starting triangle. */
+ while ((neighbor.tri != m->dummytri) && (!otriequal(neighbor, testtri))) {
+ if (infected(neighbor)) {
+ /* Mark the corner of this triangle as having been tested. */
+ setorg(neighbor, NULL);
+ }
+ else {
+ /* A live triangle. The vertex survives. */
+ killorg = 0;
+ }
+ /* Walk counterclockwise about the vertex. */
+ onextself(neighbor);
+ }
+ /* If we reached a boundary, we must walk clockwise as well. */
+ if (neighbor.tri == m->dummytri) {
+ /* Walk clockwise about the vertex. */
+ oprev(testtri, neighbor);
+ /* Stop upon reaching a boundary. */
+ while (neighbor.tri != m->dummytri) {
+ if (infected(neighbor)) {
+ /* Mark the corner of this triangle as having been tested. */
+ setorg(neighbor, NULL);
+ }
+ else {
+ /* A live triangle. The vertex survives. */
+ killorg = 0;
+ }
+ /* Walk clockwise about the vertex. */
+ oprevself(neighbor);
+ }
+ }
+ if (killorg) {
+ if (b->verbose > 1) {
+ printf(" Deleting vertex (%.12g, %.12g)\n", testvertex[0], testvertex[1]);
+ }
+ setvertextype(testvertex, UNDEADVERTEX);
+ m->undeads++;
+ }
+ }
+ }
+
+ /* Record changes in the number of boundary edges, and disconnect */
+ /* dead triangles from their neighbors. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ sym(testtri, neighbor);
+ if (neighbor.tri == m->dummytri) {
+ /* There is no neighboring triangle on this edge, so this edge */
+ /* is a boundary edge. This triangle is being deleted, so this */
+ /* boundary edge is deleted. */
+ m->hullsize--;
+ }
+ else {
+ /* Disconnect the triangle from its neighbor. */
+ dissolve(neighbor);
+ /* There is a neighboring triangle on this edge, so this edge */
+ /* becomes a boundary edge when this triangle is deleted. */
+ m->hullsize++;
+ }
+ }
+ /* Return the dead triangle to the pool of triangles. */
+ triangledealloc(m, testtri.tri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+ /* Empty the virus pool. */
+ poolrestart(&m->viri);
+}
+
+/*****************************************************************************/
+/* */
+/* regionplague() Spread regional attributes and/or area constraints */
+/* (from a .poly file) throughout the mesh. */
+/* */
+/* This procedure operates in two phases. The first phase spreads an */
+/* attribute and/or an area constraint through a (segment-bounded) region. */
+/* The triangles are marked to ensure that each triangle is added to the */
+/* virus pool only once, so the procedure will terminate. */
+/* */
+/* The second phase uninfects all infected triangles, returning them to */
+/* normal. */
+/* */
+/*****************************************************************************/
+
+void regionplague(struct mesh *m, struct behavior *b, REAL attribute, REAL area) {
+ struct otri testtri;
+ struct otri neighbor;
+ triangle **virusloop;
+ triangle **regiontri;
+ struct osub neighborsubseg;
+ vertex regionorg, regiondest, regionapex;
+ triangle ptr; /* Temporary variable used by sym() and onext(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (b->verbose > 1) {
+ printf(" Marking neighbors of marked triangles.\n");
+ }
+ /* Loop through all the infected triangles, spreading the attribute */
+ /* and/or area constraint to their neighbors, then to their neighbors' */
+ /* neighbors. */
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+ /* A triangle is marked as infected by messing with one of its pointers */
+ /* to subsegments, setting it to an illegal value. Hence, we have to */
+ /* temporarily uninfect this triangle so that we can examine its */
+ /* adjacent subsegments. */
+ uninfect(testtri);
+ if (b->regionattrib) {
+ /* Set an attribute. */
+ setelemattribute(testtri, m->eextras, attribute);
+ }
+ if (b->vararea) {
+ /* Set an area constraint. */
+ setareabound(testtri, area);
+ }
+ if (b->verbose > 2) {
+ /* Assign the triangle an orientation for convenience in */
+ /* checking its vertices. */
+ testtri.orient = 0;
+ org(testtri, regionorg);
+ dest(testtri, regiondest);
+ apex(testtri, regionapex);
+ printf( " Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+ regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+ regionapex[0], regionapex[1]);
+ }
+ /* Check each of the triangle's three neighbors. */
+ for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) {
+ /* Find the neighbor. */
+ sym(testtri, neighbor);
+ /* Check for a subsegment between the triangle and its neighbor. */
+ tspivot(testtri, neighborsubseg);
+ /* Make sure the neighbor exists, is not already infected, and */
+ /* isn't protected by a subsegment. */
+ if ((neighbor.tri != m->dummytri) && !infected(neighbor)
+ && (neighborsubseg.ss == m->dummysub)) {
+ if (b->verbose > 2) {
+ org(neighbor, regionorg);
+ dest(neighbor, regiondest);
+ apex(neighbor, regionapex);
+ printf( " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n",
+ regionorg[0], regionorg[1], regiondest[0], regiondest[1],
+ regionapex[0], regionapex[1]);
+ }
+ /* Infect the neighbor. */
+ infect(neighbor);
+ /* Ensure that the neighbor's neighbors will be infected. */
+ regiontri = (triangle **) poolalloc(&m->viri);
+ *regiontri = neighbor.tri;
+ }
+ }
+ /* Remark the triangle as infected, so it doesn't get added to the */
+ /* virus pool again. */
+ infect(testtri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+
+ /* Uninfect all triangles. */
+ if (b->verbose > 1) {
+ printf(" Unmarking marked triangles.\n");
+ }
+ traversalinit(&m->viri);
+ virusloop = (triangle **) traverse(&m->viri);
+ while (virusloop != (triangle **) NULL) {
+ testtri.tri = *virusloop;
+ uninfect(testtri);
+ virusloop = (triangle **) traverse(&m->viri);
+ }
+ /* Empty the virus pool. */
+ poolrestart(&m->viri);
+}
+
+/*****************************************************************************/
+/* */
+/* carveholes() Find the holes and infect them. Find the area */
+/* constraints and infect them. Infect the convex hull. */
+/* Spread the infection and kill triangles. Spread the */
+/* area constraints. */
+/* */
+/* This routine mainly calls other routines to carry out all these */
+/* functions. */
+/* */
+/*****************************************************************************/
+
+void carveholes(struct mesh *m, struct behavior *b, REAL *holelist, int holes, REAL *regionlist,
+ int regions) {
+ struct otri searchtri;
+ struct otri triangleloop;
+ struct otri *regiontris;
+ triangle **holetri;
+ triangle **regiontri;
+ vertex searchorg, searchdest;
+ enum locateresult intersect;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (!(b->quiet || (b->noholes && b->convex))) {
+ printf("Removing unwanted triangles.\n");
+ if (b->verbose && (holes > 0)) {
+ printf(" Marking holes for elimination.\n");
+ }
+ }
+
+ if (regions > 0) {
+ /* Allocate storage for the triangles in which region points fall. */
+ regiontris = (struct otri *) trimalloc(regions * (int) sizeof(struct otri));
+ }
+ else {
+ regiontris = (struct otri *) NULL;
+ }
+
+ if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) {
+ /* Initialize a pool of viri to be used for holes, concavities, */
+ /* regional attributes, and/or regional area constraints. */
+ poolinit(&m->viri, sizeof(triangle *), VIRUSPERBLOCK, VIRUSPERBLOCK, 0);
+ }
+
+ if (!b->convex) {
+ /* Mark as infected any unprotected triangles on the boundary. */
+ /* This is one way by which concavities are created. */
+ infecthull(m, b);
+ }
+
+ if ((holes > 0) && !b->noholes) {
+ /* Infect each triangle in which a hole lies. */
+ for (i = 0; i < 2 * holes; i += 2) {
+ /* Ignore holes that aren't within the bounds of the mesh. */
+ if ((holelist[i] >= m->xmin) && (holelist[i] <= m->xmax) && (holelist[i + 1] >= m->ymin)
+ && (holelist[i + 1] <= m->ymax)) {
+ /* Start searching from some triangle on the outer boundary. */
+ searchtri.tri = m->dummytri;
+ searchtri.orient = 0;
+ symself(searchtri);
+ /* Ensure that the hole is to the left of this boundary edge; */
+ /* otherwise, locate() will falsely report that the hole */
+ /* falls within the starting triangle. */
+ org(searchtri, searchorg);
+ dest(searchtri, searchdest);
+ if (counterclockwise(m, b, searchorg, searchdest, &holelist[i]) > 0.0) {
+ /* Find a triangle that contains the hole. */
+ intersect = locate(m, b, &holelist[i], &searchtri);
+ if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+ /* Infect the triangle. This is done by marking the triangle */
+ /* as infected and including the triangle in the virus pool. */
+ infect(searchtri);
+ holetri = (triangle **) poolalloc(&m->viri);
+ *holetri = searchtri.tri;
+ }
+ }
+ }
+ }
+ }
+
+ /* Now, we have to find all the regions BEFORE we carve the holes, because */
+ /* locate() won't work when the triangulation is no longer convex. */
+ /* (Incidentally, this is the reason why regional attributes and area */
+ /* constraints can't be used when refining a preexisting mesh, which */
+ /* might not be convex; they can only be used with a freshly */
+ /* triangulated PSLG.) */
+ if (regions > 0) {
+ /* Find the starting triangle for each region. */
+ for (i = 0; i < regions; i++) {
+ regiontris[i].tri = m->dummytri;
+ /* Ignore region points that aren't within the bounds of the mesh. */
+ if ((regionlist[4 * i] >= m->xmin) && (regionlist[4 * i] <= m->xmax)
+ && (regionlist[4 * i + 1] >= m->ymin) && (regionlist[4 * i + 1] <= m->ymax)) {
+ /* Start searching from some triangle on the outer boundary. */
+ searchtri.tri = m->dummytri;
+ searchtri.orient = 0;
+ symself(searchtri);
+ /* Ensure that the region point is to the left of this boundary */
+ /* edge; otherwise, locate() will falsely report that the */
+ /* region point falls within the starting triangle. */
+ org(searchtri, searchorg);
+ dest(searchtri, searchdest);
+ if (counterclockwise(m, b, searchorg, searchdest, ®ionlist[4 * i]) > 0.0) {
+ /* Find a triangle that contains the region point. */
+ intersect = locate(m, b, ®ionlist[4 * i], &searchtri);
+ if ((intersect != OUTSIDE) && (!infected(searchtri))) {
+ /* Record the triangle for processing after the */
+ /* holes have been carved. */
+ otricopy(searchtri, regiontris[i]);
+ }
+ }
+ }
+ }
+ }
+
+ if (m->viri.items > 0) {
+ /* Carve the holes and concavities. */
+ plague(m, b);
+ }
+ /* The virus pool should be empty now. */
+
+ if (regions > 0) {
+ if (!b->quiet) {
+ if (b->regionattrib) {
+ if (b->vararea) {
+ printf("Spreading regional attributes and area constraints.\n");
+ }
+ else {
+ printf("Spreading regional attributes.\n");
+ }
+ }
+ else {
+ printf("Spreading regional area constraints.\n");
+ }
+ }
+ if (b->regionattrib && !b->refine) {
+ /* Assign every triangle a regional attribute of zero. */
+ traversalinit(&m->triangles);
+ triangleloop.orient = 0;
+ triangleloop.tri = triangletraverse(m);
+ while (triangleloop.tri != (triangle *) NULL) {
+ setelemattribute(triangleloop, m->eextras, 0.0);
+ triangleloop.tri = triangletraverse(m);
+ }
+ }
+ for (i = 0; i < regions; i++) {
+ if (regiontris[i].tri != m->dummytri) {
+ /* Make sure the triangle under consideration still exists. */
+ /* It may have been eaten by the virus. */
+ if (!deadtri(regiontris[i].tri)) {
+ /* Put one triangle in the virus pool. */
+ infect(regiontris[i]);
+ regiontri = (triangle **) poolalloc(&m->viri);
+ *regiontri = regiontris[i].tri;
+ /* Apply one region's attribute and/or area constraint. */
+ regionplague(m, b, regionlist[4 * i + 2], regionlist[4 * i + 3]);
+ /* The virus pool should be empty now. */
+ }
+ }
+ }
+ if (b->regionattrib && !b->refine) {
+ /* Note the fact that each triangle has an additional attribute. */
+ m->eextras++;
+ }
+ }
+
+ /* Free up memory. */
+ if (((holes > 0) && !b->noholes) || !b->convex || (regions > 0)) {
+ pooldeinit(&m->viri);
+ }
+ if (regions > 0) {
+ trifree((VOID *) regiontris);
+ }
+}
+
+/** **/
+/** **/
+/********* Carving out holes and concavities ends here *********/
+
+/*****************************************************************************/
+/* */
+/* highorder() Create extra nodes for quadratic subparametric elements. */
+/* */
+/*****************************************************************************/
+
+void highorder(struct mesh *m, struct behavior *b) {
+ struct otri triangleloop, trisym;
+ struct osub checkmark;
+ vertex newvertex;
+ vertex torg, tdest;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (!b->quiet) {
+ printf("Adding vertices for second-order triangles.\n");
+ }
+ /* The following line ensures that dead items in the pool of nodes */
+ /* cannot be allocated for the extra nodes associated with high */
+ /* order elements. This ensures that the primary nodes (at the */
+ /* corners of elements) will occur earlier in the output files, and */
+ /* have lower indices, than the extra nodes. */
+ m->vertices.deaditemstack = (VOID *) NULL;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ /* To loop over the set of edges, loop over all triangles, and look at */
+ /* the three edges of each triangle. If there isn't another triangle */
+ /* adjacent to the edge, operate on the edge. If there is another */
+ /* adjacent triangle, operate on the edge only if the current triangle */
+ /* has a smaller pointer than its neighbor. This way, each edge is */
+ /* considered only once. */
+ while (triangleloop.tri != (triangle *) NULL) {
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ sym(triangleloop, trisym);
+ if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+ org(triangleloop, torg);
+ dest(triangleloop, tdest);
+ /* Create a new node in the middle of the edge. Interpolate */
+ /* its attributes. */
+ newvertex = (vertex) poolalloc(&m->vertices);
+ for (i = 0; i < 2 + m->nextras; i++) {
+ newvertex[i] = 0.5 * (torg[i] + tdest[i]);
+ }
+ /* Set the new node's marker to zero or one, depending on */
+ /* whether it lies on a boundary. */
+ setvertexmark(newvertex, trisym.tri == m->dummytri);
+ setvertextype(newvertex, trisym.tri == m->dummytri ? FREEVERTEX : SEGMENTVERTEX);
+ if (b->usesegments) {
+ tspivot(triangleloop, checkmark);
+ /* If this edge is a segment, transfer the marker to the new node. */
+ if (checkmark.ss != m->dummysub) {
+ setvertexmark(newvertex, mark(checkmark));
+ setvertextype(newvertex, SEGMENTVERTEX);
+ }
+ }
+ if (b->verbose > 1) {
+ printf(" Creating (%.12g, %.12g).\n", newvertex[0], newvertex[1]);
+ }
+ /* Record the new node in the (one or two) adjacent elements. */
+ triangleloop.tri[m->highorderindex + triangleloop.orient] = (triangle) newvertex;
+ if (trisym.tri != m->dummytri) {
+ trisym.tri[m->highorderindex + trisym.orient] = (triangle) newvertex;
+ }
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* transfernodes() Read the vertices from memory. */
+/* */
+/*****************************************************************************/
+
+void transfernodes(struct mesh *m, struct behavior *b, REAL *pointlist, REAL *pointattriblist,
+ int *pointmarkerlist, int numberofpoints, int numberofpointattribs) {
+ vertex vertexloop;
+ REAL x, y;
+ int i, j;
+ int coordindex;
+ int attribindex;
+
+ m->invertices = numberofpoints;
+ m->mesh_dim = 2;
+ m->nextras = numberofpointattribs;
+ m->readnodefile = 0;
+ if (m->invertices < 3) {
+ printf("Error: Input must have at least three input vertices.\n");
+ triexit(1);
+ }
+ if (m->nextras == 0) {
+ b->weighted = 0;
+ }
+
+ initializevertexpool(m, b);
+
+ /* Read the vertices. */
+ coordindex = 0;
+ attribindex = 0;
+ for (i = 0; i < m->invertices; i++) {
+ vertexloop = (vertex) poolalloc(&m->vertices);
+ /* Read the vertex coordinates. */
+ x = vertexloop[0] = pointlist[coordindex++];
+ y = vertexloop[1] = pointlist[coordindex++];
+ /* Read the vertex attributes. */
+ for (j = 0; j < numberofpointattribs; j++) {
+ vertexloop[2 + j] = pointattriblist[attribindex++];
+ }
+ if (pointmarkerlist != (int *) NULL) {
+ /* Read a vertex marker. */
+ setvertexmark(vertexloop, pointmarkerlist[i]);
+ }
+ else {
+ /* If no markers are specified, they default to zero. */
+ setvertexmark(vertexloop, 0);
+ }
+
+ // ----------------------------------------------
+ for (j = (i - 1) * 2; j >= 0; j -= 2){
+ if (x == pointlist[j] && y == pointlist[j+1]){
+ printf("skip duplicate %d\n", j >> 1);
+ setvertextype(vertexloop, UNDEADVERTEX);
+ vertexloop[0] = 0xffffffff;
+ vertexloop[1] = 0xffffffff;
+ break;
+ }
+ }
+ if (j >= 0)
+ continue;
+ // ----------------------------------------------
+
+ setvertextype(vertexloop, INPUTVERTEX);
+ /* Determine the smallest and largest x and y coordinates. */
+ if (i == 0) {
+ m->xmin = m->xmax = x;
+ m->ymin = m->ymax = y;
+ }
+ else {
+ m->xmin = (x < m->xmin) ? x : m->xmin;
+ m->xmax = (x > m->xmax) ? x : m->xmax;
+ m->ymin = (y < m->ymin) ? y : m->ymin;
+ m->ymax = (y > m->ymax) ? y : m->ymax;
+ }
+ }
+
+ /* Nonexistent x value used as a flag to mark circle events in sweepline */
+ /* Delaunay algorithm. */
+ m->xminextreme = 10 * m->xmin - 9 * m->xmax;
+}
+
+/*****************************************************************************/
+/* */
+/* writenodes() Number the vertices and write them to a .node file. */
+/* */
+/* To save memory, the vertex numbers are written over the boundary markers */
+/* after the vertices are written to a file. */
+/* */
+/*****************************************************************************/
+
+void writenodes(struct mesh *m, struct behavior *b, REAL **pointlist, REAL **pointattriblist,
+ int **pointmarkerlist) {
+ REAL *plist;
+ REAL *palist;
+ int *pmlist;
+ int coordindex;
+ int attribindex;
+ vertex vertexloop;
+ long outvertices;
+ int vertexnumber;
+ int i;
+
+ if (b->jettison) {
+ outvertices = m->vertices.items - m->undeads;
+ }
+ else {
+ outvertices = m->vertices.items;
+ }
+
+ if (!b->quiet) {
+ printf("Writing vertices.\n");
+ }
+ /* Allocate memory for output vertices if necessary. */
+ if (*pointlist == (REAL *) NULL) {
+ *pointlist = (REAL *) trimalloc((int) (outvertices * 2 * sizeof(REAL)));
+ }
+ /* Allocate memory for output vertex attributes if necessary. */
+ if ((m->nextras > 0) && (*pointattriblist == (REAL *) NULL)) {
+ *pointattriblist = (REAL *) trimalloc((int) (outvertices * m->nextras * sizeof(REAL)));
+ }
+ /* Allocate memory for output vertex markers if necessary. */
+ if (!b->nobound && (*pointmarkerlist == (int *) NULL)) {
+ *pointmarkerlist = (int *) trimalloc((int) (outvertices * sizeof(int)));
+ }
+ plist = *pointlist;
+ palist = *pointattriblist;
+ pmlist = *pointmarkerlist;
+ coordindex = 0;
+ attribindex = 0;
+
+ traversalinit(&m->vertices);
+ vertexnumber = b->firstnumber;
+ vertexloop = vertextraverse(m);
+ while (vertexloop != (vertex) NULL) {
+ if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) {
+ /* X and y coordinates. */
+ plist[coordindex++] = vertexloop[0];
+ plist[coordindex++] = vertexloop[1];
+ /* Vertex attributes. */
+ for (i = 0; i < m->nextras; i++) {
+ palist[attribindex++] = vertexloop[2 + i];
+ }
+ if (!b->nobound) {
+ /* Copy the boundary marker. */
+ pmlist[vertexnumber - b->firstnumber] = vertexmark(vertexloop);
+ }
+ setvertexmark(vertexloop, vertexnumber);
+ vertexnumber++;
+ }
+ vertexloop = vertextraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* numbernodes() Number the vertices. */
+/* */
+/* Each vertex is assigned a marker equal to its number. */
+/* */
+/* Used when writenodes() is not called because no .node file is written. */
+/* */
+/*****************************************************************************/
+
+void numbernodes(struct mesh *m, struct behavior *b) {
+ vertex vertexloop;
+ int vertexnumber;
+
+ traversalinit(&m->vertices);
+ vertexnumber = b->firstnumber;
+ vertexloop = vertextraverse(m);
+ while (vertexloop != (vertex) NULL) {
+ setvertexmark(vertexloop, vertexnumber);
+ if (!b->jettison || (vertextype(vertexloop) != UNDEADVERTEX)) {
+ vertexnumber++;
+ }
+ vertexloop = vertextraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writeelements() Write the triangles to an .ele file. */
+/* */
+/*****************************************************************************/
+
+void writeelements(struct mesh *m, struct behavior *b, INDICE **trianglelist,
+ REAL **triangleattriblist) {
+ INDICE *tlist;
+ REAL *talist;
+ int vertexindex;
+ int attribindex;
+ struct otri triangleloop;
+ vertex p1, p2, p3;
+ vertex mid1, mid2, mid3;
+ long elementnumber;
+ int i;
+
+ if (!b->quiet) {
+ printf("Writing triangles.\n");
+ }
+ /* Allocate memory for output triangles if necessary. */
+ if (*trianglelist == (INDICE *) NULL) {
+ *trianglelist = (INDICE *) trimalloc(
+ (INDICE) (m->triangles.items * ((b->order + 1) * (b->order + 2) / 2) * sizeof(int)));
+ }
+ /* Allocate memory for output triangle attributes if necessary. */
+ if ((m->eextras > 0) && (*triangleattriblist == (REAL *) NULL)) {
+ *triangleattriblist = (REAL *) trimalloc(
+ (int) (m->triangles.items * m->eextras * sizeof(REAL)));
+ }
+ tlist = *trianglelist;
+ talist = *triangleattriblist;
+ vertexindex = 0;
+ attribindex = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ elementnumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ org(triangleloop, p1);
+ dest(triangleloop, p2);
+ apex(triangleloop, p3);
+ if (b->order == 1) {
+ tlist[vertexindex++] = vertexmark(p1);
+ tlist[vertexindex++] = vertexmark(p2);
+ tlist[vertexindex++] = vertexmark(p3);
+ }
+ else {
+ mid1 = (vertex) triangleloop.tri[m->highorderindex + 1];
+ mid2 = (vertex) triangleloop.tri[m->highorderindex + 2];
+ mid3 = (vertex) triangleloop.tri[m->highorderindex];
+ tlist[vertexindex++] = vertexmark(p1);
+ tlist[vertexindex++] = vertexmark(p2);
+ tlist[vertexindex++] = vertexmark(p3);
+ tlist[vertexindex++] = vertexmark(mid1);
+ tlist[vertexindex++] = vertexmark(mid2);
+ tlist[vertexindex++] = vertexmark(mid3);
+ }
+
+ for (i = 0; i < m->eextras; i++) {
+ talist[attribindex++] = elemattribute(triangleloop, i);
+ }
+
+ triangleloop.tri = triangletraverse(m);
+ elementnumber++;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writepoly() Write the segments and holes to a .poly file. */
+/* */
+/*****************************************************************************/
+
+void writepoly(struct mesh *m, struct behavior *b, int **segmentlist, int **segmentmarkerlist) {
+ int *slist;
+ int *smlist;
+ int index;
+ struct osub subsegloop;
+ vertex endpoint1, endpoint2;
+ long subsegnumber;
+
+ if (!b->quiet) {
+ printf("Writing segments.\n");
+ }
+ /* Allocate memory for output segments if necessary. */
+ if (*segmentlist == (int *) NULL) {
+ *segmentlist = (int *) trimalloc((int) (m->subsegs.items * 2 * sizeof(int)));
+ }
+ /* Allocate memory for output segment markers if necessary. */
+ if (!b->nobound && (*segmentmarkerlist == (int *) NULL)) {
+ *segmentmarkerlist = (int *) trimalloc((int) (m->subsegs.items * sizeof(int)));
+ }
+ slist = *segmentlist;
+ smlist = *segmentmarkerlist;
+ index = 0;
+
+ traversalinit(&m->subsegs);
+ subsegloop.ss = subsegtraverse(m);
+ subsegloop.ssorient = 0;
+ subsegnumber = b->firstnumber;
+ while (subsegloop.ss != (subseg *) NULL) {
+ sorg(subsegloop, endpoint1);
+ sdest(subsegloop, endpoint2);
+ /* Copy indices of the segment's two endpoints. */
+ slist[index++] = vertexmark(endpoint1);
+ slist[index++] = vertexmark(endpoint2);
+ if (!b->nobound) {
+ /* Copy the boundary marker. */
+ smlist[subsegnumber - b->firstnumber] = mark(subsegloop);
+ }
+
+ subsegloop.ss = subsegtraverse(m);
+ subsegnumber++;
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writeedges() Write the edges to an .edge file. */
+/* */
+/*****************************************************************************/
+
+void writeedges(struct mesh *m, struct behavior *b, int **edgelist, int **edgemarkerlist) {
+ int *elist;
+ int *emlist;
+ int index;
+ struct otri triangleloop, trisym;
+ struct osub checkmark;
+ vertex p1, p2;
+ long edgenumber;
+ triangle ptr; /* Temporary variable used by sym(). */
+ subseg sptr; /* Temporary variable used by tspivot(). */
+
+ if (!b->quiet) {
+ printf("Writing edges.\n");
+ }
+ /* Allocate memory for edges if necessary. */
+ if (*edgelist == (int *) NULL) {
+ *edgelist = (int *) trimalloc((int) (m->edges * 2 * sizeof(int)));
+ }
+ /* Allocate memory for edge markers if necessary. */
+ if (!b->nobound && (*edgemarkerlist == (int *) NULL)) {
+ *edgemarkerlist = (int *) trimalloc((int) (m->edges * sizeof(int)));
+ }
+ elist = *edgelist;
+ emlist = *edgemarkerlist;
+ index = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ edgenumber = b->firstnumber;
+ /* To loop over the set of edges, loop over all triangles, and look at */
+ /* the three edges of each triangle. If there isn't another triangle */
+ /* adjacent to the edge, operate on the edge. If there is another */
+ /* adjacent triangle, operate on the edge only if the current triangle */
+ /* has a smaller pointer than its neighbor. This way, each edge is */
+ /* considered only once. */
+ while (triangleloop.tri != (triangle *) NULL) {
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ sym(triangleloop, trisym);
+ if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+ org(triangleloop, p1);
+ dest(triangleloop, p2);
+ elist[index++] = vertexmark(p1);
+ elist[index++] = vertexmark(p2);
+ if (b->nobound) {
+ }
+ else {
+ /* Edge number, indices of two endpoints, and a boundary marker. */
+ /* If there's no subsegment, the boundary marker is zero. */
+ if (b->usesegments) {
+ tspivot(triangleloop, checkmark);
+ if (checkmark.ss == m->dummysub) {
+ emlist[edgenumber - b->firstnumber] = 0;
+ }
+ else {
+ emlist[edgenumber - b->firstnumber] = mark(checkmark);
+ }
+ }
+ else {
+ emlist[edgenumber - b->firstnumber] = trisym.tri == m->dummytri;
+ }
+ }
+ edgenumber++;
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* writevoronoi() Write the Voronoi diagram to a .v.node and .v.edge */
+/* file. */
+/* */
+/* The Voronoi diagram is the geometric dual of the Delaunay triangulation. */
+/* Hence, the Voronoi vertices are listed by traversing the Delaunay */
+/* triangles, and the Voronoi edges are listed by traversing the Delaunay */
+/* edges. */
+/* */
+/* WARNING: In order to assign numbers to the Voronoi vertices, this */
+/* procedure messes up the subsegments or the extra nodes of every */
+/* element. Hence, you should call this procedure last. */
+/* */
+/*****************************************************************************/
+
+void writevoronoi(struct mesh *m, struct behavior *b, REAL **vpointlist, REAL **vpointattriblist,
+ int **vpointmarkerlist, int **vedgelist, int **vedgemarkerlist, REAL **vnormlist) {
+ REAL *plist;
+ REAL *palist;
+ int *elist;
+ REAL *normlist;
+ int coordindex;
+ int attribindex;
+ struct otri triangleloop, trisym;
+ vertex torg, tdest, tapex;
+ REAL circumcenter[2];
+ REAL xi, eta;
+ long vnodenumber, vedgenumber;
+ int p1, p2;
+ int i;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (!b->quiet) {
+ printf("Writing Voronoi vertices.\n");
+ }
+ /* Allocate memory for Voronoi vertices if necessary. */
+ if (*vpointlist == (REAL *) NULL) {
+ *vpointlist = (REAL *) trimalloc((int) (m->triangles.items * 2 * sizeof(REAL)));
+ }
+ /* Allocate memory for Voronoi vertex attributes if necessary. */
+ if (*vpointattriblist == (REAL *) NULL) {
+ *vpointattriblist = (REAL *) trimalloc(
+ (int) (m->triangles.items * m->nextras * sizeof(REAL)));
+ }
+ *vpointmarkerlist = (int *) NULL;
+ plist = *vpointlist;
+ palist = *vpointattriblist;
+ coordindex = 0;
+ attribindex = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ vnodenumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ org(triangleloop, torg);
+ dest(triangleloop, tdest);
+ apex(triangleloop, tapex);
+ findcircumcenter(m, b, torg, tdest, tapex, circumcenter, &xi, &eta, 0);
+ /* X and y coordinates. */
+ plist[coordindex++] = circumcenter[0];
+ plist[coordindex++] = circumcenter[1];
+ for (i = 2; i < 2 + m->nextras; i++) {
+ /* Interpolate the vertex attributes at the circumcenter. */
+ palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i]) + eta * (tapex[i] - torg[i]);
+ }
+
+ *(int *) (triangleloop.tri + 6) = (int) vnodenumber;
+ triangleloop.tri = triangletraverse(m);
+ vnodenumber++;
+ }
+
+ if (!b->quiet) {
+ printf("Writing Voronoi edges.\n");
+ }
+ /* Allocate memory for output Voronoi edges if necessary. */
+ if (*vedgelist == (int *) NULL) {
+ *vedgelist = (int *) trimalloc((int) (m->edges * 2 * sizeof(int)));
+ }
+ *vedgemarkerlist = (int *) NULL;
+ /* Allocate memory for output Voronoi norms if necessary. */
+ if (*vnormlist == (REAL *) NULL) {
+ *vnormlist = (REAL *) trimalloc((int) (m->edges * 2 * sizeof(REAL)));
+ }
+ elist = *vedgelist;
+ normlist = *vnormlist;
+ coordindex = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ vedgenumber = b->firstnumber;
+ /* To loop over the set of edges, loop over all triangles, and look at */
+ /* the three edges of each triangle. If there isn't another triangle */
+ /* adjacent to the edge, operate on the edge. If there is another */
+ /* adjacent triangle, operate on the edge only if the current triangle */
+ /* has a smaller pointer than its neighbor. This way, each edge is */
+ /* considered only once. */
+ while (triangleloop.tri != (triangle *) NULL) {
+ for (triangleloop.orient = 0; triangleloop.orient < 3; triangleloop.orient++) {
+ sym(triangleloop, trisym);
+ if ((triangleloop.tri < trisym.tri) || (trisym.tri == m->dummytri)) {
+ /* Find the number of this triangle (and Voronoi vertex). */
+ p1 = *(int *) (triangleloop.tri + 6);
+ if (trisym.tri == m->dummytri) {
+ org(triangleloop, torg);
+ dest(triangleloop, tdest);
+ /* Copy an infinite ray. Index of one endpoint, and -1. */
+ elist[coordindex] = p1;
+ normlist[coordindex++] = tdest[1] - torg[1];
+ elist[coordindex] = -1;
+ normlist[coordindex++] = torg[0] - tdest[0];
+ }
+ else {
+ /* Find the number of the adjacent triangle (and Voronoi vertex). */
+ p2 = *(int *) (trisym.tri + 6);
+ /* Finite edge. Write indices of two endpoints. */
+ elist[coordindex] = p1;
+ normlist[coordindex++] = 0.0;
+ elist[coordindex] = p2;
+ normlist[coordindex++] = 0.0;
+ }
+ vedgenumber++;
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+}
+
+void writeneighbors(struct mesh *m, struct behavior *b, int **neighborlist) {
+ int *nlist;
+ int index;
+ struct otri triangleloop, trisym;
+ long elementnumber;
+ int neighbor1, neighbor2, neighbor3;
+ triangle ptr; /* Temporary variable used by sym(). */
+
+ if (!b->quiet) {
+ printf("Writing neighbors.\n");
+ }
+ /* Allocate memory for neighbors if necessary. */
+ if (*neighborlist == (int *) NULL) {
+ *neighborlist = (int *) trimalloc((int) (m->triangles.items * 3 * sizeof(int)));
+ }
+ nlist = *neighborlist;
+ index = 0;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ elementnumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ *(int *) (triangleloop.tri + 6) = (int) elementnumber;
+ triangleloop.tri = triangletraverse(m);
+ elementnumber++;
+ }
+ *(int *) (m->dummytri + 6) = -1;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ elementnumber = b->firstnumber;
+ while (triangleloop.tri != (triangle *) NULL) {
+ triangleloop.orient = 1;
+ sym(triangleloop, trisym);
+ neighbor1 = *(int *) (trisym.tri + 6);
+ triangleloop.orient = 2;
+ sym(triangleloop, trisym);
+ neighbor2 = *(int *) (trisym.tri + 6);
+ triangleloop.orient = 0;
+ sym(triangleloop, trisym);
+ neighbor3 = *(int *) (trisym.tri + 6);
+ nlist[index++] = neighbor1;
+ nlist[index++] = neighbor2;
+ nlist[index++] = neighbor3;
+
+ triangleloop.tri = triangletraverse(m);
+ elementnumber++;
+ }
+}
+
+/** **/
+/** **/
+/********* File I/O routines end here *********/
+
+/*****************************************************************************/
+/* */
+/* main() or triangulate() Gosh, do everything. */
+/* */
+/* The sequence is roughly as follows. Many of these steps can be skipped, */
+/* depending on the command line switches. */
+/* */
+/* - Initialize constants and parse the command line. */
+/* - Read the vertices from a file and either */
+/* - triangulate them (no -r), or */
+/* - read an old mesh from files and reconstruct it (-r). */
+/* - Insert the PSLG segments (-p), and possibly segments on the convex */
+/* hull (-c). */
+/* - Read the holes (-p), regional attributes (-pA), and regional area */
+/* constraints (-pa). Carve the holes and concavities, and spread the */
+/* regional attributes and area constraints. */
+/* - Enforce the constraints on minimum angle (-q) and maximum area (-a). */
+/* Also enforce the conforming Delaunay property (-q and -a). */
+/* - Compute the number of edges in the resulting mesh. */
+/* - Promote the mesh's linear triangles to higher order elements (-o). */
+/* - Write the output files and print the statistics. */
+/* - Check the consistency and Delaunay property of the mesh (-C). */
+/* */
+/*****************************************************************************/
+
+void triangulate(struct behavior *command, struct triangulateio *in, struct triangulateio *out,
+ struct triangulateio *vorout) {
+ struct mesh m;
+ struct behavior *b = command;
+ REAL *holearray; /* Array of holes. */
+ REAL *regionarray; /* Array of regional attributes and area constraints. */
+
+ triangleinit(&m);
+ //parsecommandline(1, &triswitches, &b);
+ m.steinerleft = b->steiner;
+
+ transfernodes(&m, b, in->pointlist, in->pointattributelist, in->pointmarkerlist,
+ in->numberofpoints, in->numberofpointattributes);
+
+#ifdef CDT_ONLY
+ m.hullsize = delaunay(&m, b); /* Triangulate the vertices. */
+#else /* not CDT_ONLY */
+ if (b->refine)
+ {
+ /* Read and reconstruct a mesh. */
+ m.hullsize = reconstruct(&m, b, in->trianglelist,
+ in->triangleattributelist, in->trianglearealist,
+ in->numberoftriangles, in->numberofcorners,
+ in->numberoftriangleattributes,
+ in->segmentlist, in->segmentmarkerlist,
+ in->numberofsegments);
+ }
+ else
+ {
+ m.hullsize = delaunay(&m, b); /* Triangulate the vertices. */
+ }
+#endif /* not CDT_ONLY */
+
+ /* Ensure that no vertex can be mistaken for a triangular bounding */
+ /* box vertex in insertvertex(). */
+ m.infvertex1 = (vertex) NULL;
+ m.infvertex2 = (vertex) NULL;
+ m.infvertex3 = (vertex) NULL;
+
+ if (b->usesegments) {
+ m.checksegments = 1; /* Segments will be introduced next. */
+ if (!b->refine) {
+ /* Insert PSLG segments and/or convex hull segments. */
+ formskeleton(&m, b, in->segmentlist, in->segmentmarkerlist, in->numberofsegments);
+ }
+ }
+
+ if (b->poly && (m.triangles.items > 0)) {
+ holearray = in->holelist;
+ m.holes = in->numberofholes;
+ regionarray = in->regionlist;
+ m.regions = in->numberofregions;
+ if (!b->refine) {
+ /* Carve out holes and concavities. */
+ carveholes(&m, b, holearray, m.holes, regionarray, m.regions);
+ }
+ }
+ else {
+ /* Without a PSLG, there can be no holes or regional attributes */
+ /* or area constraints. The following are set to zero to avoid */
+ /* an accidental free() later. */
+ m.holes = 0;
+ m.regions = 0;
+ }
+
+#ifndef CDT_ONLY
+ if (b->quality && (m.triangles.items > 0))
+ {
+ enforcequality(&m, b); /* Enforce angle and area constraints. */
+ }
+#endif /* not CDT_ONLY */
+
+#ifndef CDT_ONLY
+ if (b->quality)
+ {
+ printf("Quality milliseconds: %ld\n",
+ 1000l * (tv5.tv_sec - tv4.tv_sec) +
+ (tv5.tv_usec - tv4.tv_usec) / 1000l);
+ }
+#endif /* not CDT_ONLY */
+
+ /* Calculate the number of edges. */
+ m.edges = (3l * m.triangles.items + m.hullsize) / 2l;
+
+ if (b->order > 1) {
+ highorder(&m, b); /* Promote elements to higher polynomial order. */
+ }
+ if (!b->quiet) {
+ printf("\n");
+ }
+
+ if (b->jettison) {
+ out->numberofpoints = m.vertices.items - m.undeads;
+ }
+ else {
+ out->numberofpoints = m.vertices.items;
+ }
+ out->numberofpointattributes = m.nextras;
+ out->numberoftriangles = m.triangles.items;
+ out->numberofcorners = (b->order + 1) * (b->order + 2) / 2;
+ out->numberoftriangleattributes = m.eextras;
+ out->numberofedges = m.edges;
+ if (b->usesegments) {
+ out->numberofsegments = m.subsegs.items;
+ }
+ else {
+ out->numberofsegments = m.hullsize;
+ }
+ if (vorout != (struct triangulateio *) NULL) {
+ vorout->numberofpoints = m.triangles.items;
+ vorout->numberofpointattributes = m.nextras;
+ vorout->numberofedges = m.edges;
+ }
+
+ /* If not using iteration numbers, don't write a .node file if one was */
+ /* read, because the original one would be overwritten! */
+ if (b->nonodewritten || (b->noiterationnum && m.readnodefile)) {
+ if (!b->quiet) {
+ printf("NOT writing vertices.\n");
+ }
+ numbernodes(&m, b); /* We must remember to number the vertices. */
+ }
+ else {
+ /* writenodes() numbers the vertices too. */
+ writenodes(&m, b, &out->pointlist, &out->pointattributelist, &out->pointmarkerlist);
+ }
+ if (b->noelewritten) {
+ if (!b->quiet) {
+ printf("NOT writing triangles.\n");
+ }
+ }
+ else {
+ writeelements(&m, b, &out->trianglelist, &out->triangleattributelist);
+ }
+ /* The -c switch (convex switch) causes a PSLG to be written */
+ /* even if none was read. */
+ if (b->poly || b->convex) {
+ /* If not using iteration numbers, don't overwrite the .poly file. */
+ if (b->nopolywritten || b->noiterationnum) {
+ if (!b->quiet) {
+ printf("NOT writing segments.\n");
+ }
+ }
+ else {
+ writepoly(&m, b, &out->segmentlist, &out->segmentmarkerlist);
+ out->numberofholes = m.holes;
+ out->numberofregions = m.regions;
+ if (b->poly) {
+ out->holelist = in->holelist;
+ out->regionlist = in->regionlist;
+ }
+ else {
+ out->holelist = (REAL *) NULL;
+ out->regionlist = (REAL *) NULL;
+ }
+ }
+ }
+ if (b->edgesout) {
+ writeedges(&m, b, &out->edgelist, &out->edgemarkerlist);
+ }
+ if (b->voronoi) {
+ writevoronoi(&m, b, &vorout->pointlist, &vorout->pointattributelist, &vorout->pointmarkerlist,
+ &vorout->edgelist, &vorout->edgemarkerlist, &vorout->normlist);
+ }
+ if (b->neighbors) {
+ writeneighbors(&m, b, &out->neighborlist);
+ }
+
+ if (!b->quiet) {
+ statistics(&m, b);
+ }
+
+#ifndef REDUCED
+ if (b->docheck)
+ {
+ checkmesh(&m, b);
+ checkdelaunay(&m, b);
+ }
+#endif /* not REDUCED */
+
+ triangledeinit(&m, b);
+}
diff --git a/vtm/jni/triangle/triangle.h b/vtm/jni/triangle/triangle.h
new file mode 100644
index 00000000..4112a2e3
--- /dev/null
+++ b/vtm/jni/triangle/triangle.h
@@ -0,0 +1,360 @@
+/*****************************************************************************/
+/* */
+/* (triangle.h) */
+/* */
+/* Include file for programs that call Triangle. */
+/* */
+/* Accompanies Triangle Version 1.6 */
+/* July 28, 2005 */
+/* */
+/* Copyright 1996, 2005 */
+/* Jonathan Richard Shewchuk */
+/* 2360 Woolsey #H */
+/* Berkeley, California 94705-1927 */
+/* jrs@cs.berkeley.edu */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* */
+/* How to call Triangle from another program */
+/* */
+/* */
+/* If you haven't read Triangle's instructions (run "triangle -h" to read */
+/* them), you won't understand what follows. */
+/* */
+/* Triangle must be compiled into an object file (triangle.o) with the */
+/* TRILIBRARY symbol defined (generally by using the -DTRILIBRARY compiler */
+/* switch). The makefile included with Triangle will do this for you if */
+/* you run "make trilibrary". The resulting object file can be called via */
+/* the procedure triangulate(). */
+/* */
+/* If the size of the object file is important to you, you may wish to */
+/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */
+/* of all features that are primarily of research interest. Specifically, */
+/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */
+/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */
+/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */
+/* eliminates Triangle's -r, -q, -a, -u, -D, -Y, -S, and -s switches. */
+/* */
+/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */
+/* made in the makefile or in triangle.c itself. Putting these definitions */
+/* in this file (triangle.h) will not create the desired effect. */
+/* */
+/* */
+/* The calling convention for triangulate() follows. */
+/* */
+/* void triangulate(triswitches, in, out, vorout) */
+/* char *triswitches; */
+/* struct triangulateio *in; */
+/* struct triangulateio *out; */
+/* struct triangulateio *vorout; */
+/* */
+/* `triswitches' is a string containing the command line switches you wish */
+/* to invoke. No initial dash is required. Some suggestions: */
+/* */
+/* - You'll probably find it convenient to use the `z' switch so that */
+/* points (and other items) are numbered from zero. This simplifies */
+/* indexing, because the first item of any type always starts at index */
+/* [0] of the corresponding array, whether that item's number is zero or */
+/* one. */
+/* - You'll probably want to use the `Q' (quiet) switch in your final code, */
+/* but you can take advantage of Triangle's printed output (including the */
+/* `V' switch) while debugging. */
+/* - If you are not using the `q', `a', `u', `D', `j', or `s' switches, */
+/* then the output points will be identical to the input points, except */
+/* possibly for the boundary markers. If you don't need the boundary */
+/* markers, you should use the `N' (no nodes output) switch to save */
+/* memory. (If you do need boundary markers, but need to save memory, a */
+/* good nasty trick is to set out->pointlist equal to in->pointlist */
+/* before calling triangulate(), so that Triangle overwrites the input */
+/* points with identical copies.) */
+/* - The `I' (no iteration numbers) and `g' (.off file output) switches */
+/* have no effect when Triangle is compiled with TRILIBRARY defined. */
+/* */
+/* `in', `out', and `vorout' are descriptions of the input, the output, */
+/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */
+/* `vorout' may be NULL. `in' and `out' may never be NULL. */
+/* */
+/* Certain fields of the input and output structures must be initialized, */
+/* as described below. */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* */
+/* The `triangulateio' structure. */
+/* */
+/* Used to pass data into and out of the triangulate() procedure. */
+/* */
+/* */
+/* Arrays are used to store points, triangles, markers, and so forth. In */
+/* all cases, the first item in any array is stored starting at index [0]. */
+/* However, that item is item number `1' unless the `z' switch is used, in */
+/* which case it is item number `0'. Hence, you may find it easier to */
+/* index points (and triangles in the neighbor list) if you use the `z' */
+/* switch. Unless, of course, you're calling Triangle from a Fortran */
+/* program. */
+/* */
+/* Description of fields (except the `numberof' fields, which are obvious): */
+/* */
+/* `pointlist': An array of point coordinates. The first point's x */
+/* coordinate is at index [0] and its y coordinate at index [1], followed */
+/* by the coordinates of the remaining points. Each point occupies two */
+/* REALs. */
+/* `pointattributelist': An array of point attributes. Each point's */
+/* attributes occupy `numberofpointattributes' REALs. */
+/* `pointmarkerlist': An array of point markers; one int per point. */
+/* */
+/* `trianglelist': An array of triangle corners. The first triangle's */
+/* first corner is at index [0], followed by its other two corners in */
+/* counterclockwise order, followed by any other nodes if the triangle */
+/* represents a nonlinear element. Each triangle occupies */
+/* `numberofcorners' ints. */
+/* `triangleattributelist': An array of triangle attributes. Each */
+/* triangle's attributes occupy `numberoftriangleattributes' REALs. */
+/* `trianglearealist': An array of triangle area constraints; one REAL per */
+/* triangle. Input only. */
+/* `neighborlist': An array of triangle neighbors; three ints per */
+/* triangle. Output only. */
+/* */
+/* `segmentlist': An array of segment endpoints. The first segment's */
+/* endpoints are at indices [0] and [1], followed by the remaining */
+/* segments. Two ints per segment. */
+/* `segmentmarkerlist': An array of segment markers; one int per segment. */
+/* */
+/* `holelist': An array of holes. The first hole's x and y coordinates */
+/* are at indices [0] and [1], followed by the remaining holes. Two */
+/* REALs per hole. Input only, although the pointer is copied to the */
+/* output structure for your convenience. */
+/* */
+/* `regionlist': An array of regional attributes and area constraints. */
+/* The first constraint's x and y coordinates are at indices [0] and [1], */
+/* followed by the regional attribute at index [2], followed by the */
+/* maximum area at index [3], followed by the remaining area constraints. */
+/* Four REALs per area constraint. Note that each regional attribute is */
+/* used only if you select the `A' switch, and each area constraint is */
+/* used only if you select the `a' switch (with no number following), but */
+/* omitting one of these switches does not change the memory layout. */
+/* Input only, although the pointer is copied to the output structure for */
+/* your convenience. */
+/* */
+/* `edgelist': An array of edge endpoints. The first edge's endpoints are */
+/* at indices [0] and [1], followed by the remaining edges. Two ints per */
+/* edge. Output only. */
+/* `edgemarkerlist': An array of edge markers; one int per edge. Output */
+/* only. */
+/* `normlist': An array of normal vectors, used for infinite rays in */
+/* Voronoi diagrams. The first normal vector's x and y magnitudes are */
+/* at indices [0] and [1], followed by the remaining vectors. For each */
+/* finite edge in a Voronoi diagram, the normal vector written is the */
+/* zero vector. Two REALs per edge. Output only. */
+/* */
+/* */
+/* Any input fields that Triangle will examine must be initialized. */
+/* Furthermore, for each output array that Triangle will write to, you */
+/* must either provide space by setting the appropriate pointer to point */
+/* to the space you want the data written to, or you must initialize the */
+/* pointer to NULL, which tells Triangle to allocate space for the results. */
+/* The latter option is preferable, because Triangle always knows exactly */
+/* how much space to allocate. The former option is provided mainly for */
+/* people who need to call Triangle from Fortran code, though it also makes */
+/* possible some nasty space-saving tricks, like writing the output to the */
+/* same arrays as the input. */
+/* */
+/* Triangle will not free() any input or output arrays, including those it */
+/* allocates itself; that's up to you. You should free arrays allocated by */
+/* Triangle by calling the trifree() procedure defined below. (By default, */
+/* trifree() just calls the standard free() library procedure, but */
+/* applications that call triangulate() may replace trimalloc() and */
+/* trifree() in triangle.c to use specialized memory allocators.) */
+/* */
+/* Here's a guide to help you decide which fields you must initialize */
+/* before you call triangulate(). */
+/* */
+/* `in': */
+/* */
+/* - `pointlist' must always point to a list of points; `numberofpoints' */
+/* and `numberofpointattributes' must be properly set. */
+/* `pointmarkerlist' must either be set to NULL (in which case all */
+/* markers default to zero), or must point to a list of markers. If */
+/* `numberofpointattributes' is not zero, `pointattributelist' must */
+/* point to a list of point attributes. */
+/* - If the `r' switch is used, `trianglelist' must point to a list of */
+/* triangles, and `numberoftriangles', `numberofcorners', and */
+/* `numberoftriangleattributes' must be properly set. If */
+/* `numberoftriangleattributes' is not zero, `triangleattributelist' */
+/* must point to a list of triangle attributes. If the `a' switch is */
+/* used (with no number following), `trianglearealist' must point to a */
+/* list of triangle area constraints. `neighborlist' may be ignored. */
+/* - If the `p' switch is used, `segmentlist' must point to a list of */
+/* segments, `numberofsegments' must be properly set, and */
+/* `segmentmarkerlist' must either be set to NULL (in which case all */
+/* markers default to zero), or must point to a list of markers. */
+/* - If the `p' switch is used without the `r' switch, then */
+/* `numberofholes' and `numberofregions' must be properly set. If */
+/* `numberofholes' is not zero, `holelist' must point to a list of */
+/* holes. If `numberofregions' is not zero, `regionlist' must point to */
+/* a list of region constraints. */
+/* - If the `p' switch is used, `holelist', `numberofholes', */
+/* `regionlist', and `numberofregions' is copied to `out'. (You can */
+/* nonetheless get away with not initializing them if the `r' switch is */
+/* used.) */
+/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */
+/* ignored. */
+/* */
+/* `out': */
+/* */
+/* - `pointlist' must be initialized (NULL or pointing to memory) unless */
+/* the `N' switch is used. `pointmarkerlist' must be initialized */
+/* unless the `N' or `B' switch is used. If `N' is not used and */
+/* `in->numberofpointattributes' is not zero, `pointattributelist' must */
+/* be initialized. */
+/* - `trianglelist' must be initialized unless the `E' switch is used. */
+/* `neighborlist' must be initialized if the `n' switch is used. If */
+/* the `E' switch is not used and (`in->numberofelementattributes' is */
+/* not zero or the `A' switch is used), `elementattributelist' must be */
+/* initialized. `trianglearealist' may be ignored. */
+/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */
+/* and the `P' switch is not used. `segmentmarkerlist' must also be */
+/* initialized under these circumstances unless the `B' switch is used. */
+/* - `edgelist' must be initialized if the `e' switch is used. */
+/* `edgemarkerlist' must be initialized if the `e' switch is used and */
+/* the `B' switch is not. */
+/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/
+/* */
+/* `vorout' (only needed if `v' switch is used): */
+/* */
+/* - `pointlist' must be initialized. If `in->numberofpointattributes' */
+/* is not zero, `pointattributelist' must be initialized. */
+/* `pointmarkerlist' may be ignored. */
+/* - `edgelist' and `normlist' must both be initialized. */
+/* `edgemarkerlist' may be ignored. */
+/* - Everything else may be ignored. */
+/* */
+/* After a call to triangulate(), the valid fields of `out' and `vorout' */
+/* will depend, in an obvious way, on the choice of switches used. Note */
+/* that when the `p' switch is used, the pointers `holelist' and */
+/* `regionlist' are copied from `in' to `out', but no new space is */
+/* allocated; be careful that you don't free() the same array twice. On */
+/* the other hand, Triangle will never copy the `pointlist' pointer (or any */
+/* others); new space is allocated for `out->pointlist', or if the `N' */
+/* switch is used, `out->pointlist' remains uninitialized. */
+/* */
+/* All of the meaningful `numberof' fields will be properly set; for */
+/* instance, `numberofedges' will represent the number of edges in the */
+/* triangulation whether or not the edges were written. If segments are */
+/* not used, `numberofsegments' will indicate the number of boundary edges. */
+/* */
+/*****************************************************************************/
+
+#define SINGLE
+
+#ifdef SINGLE
+#define REAL float
+#else /* not SINGLE */
+#define REAL double
+#endif /* not SINGLE */
+
+#define INDICE unsigned short
+
+typedef struct triangulateio TriangleIO;
+
+struct triangulateio {
+ REAL *pointlist; /* In / out */
+ REAL *pointattributelist; /* In / out */
+ int *pointmarkerlist; /* In / out */
+ int numberofpoints; /* In / out */
+ int numberofpointattributes; /* In / out */
+
+ INDICE *trianglelist; /* In / out */
+ REAL *triangleattributelist; /* In / out */
+ REAL *trianglearealist; /* In only */
+ int *neighborlist; /* Out only */
+ int numberoftriangles; /* In / out */
+ int numberofcorners; /* In / out */
+ int numberoftriangleattributes; /* In / out */
+
+ int *segmentlist; /* In / out */
+ int *segmentmarkerlist; /* In / out */
+ int numberofsegments; /* In / out */
+
+ REAL *holelist; /* In / pointer to array copied out */
+ int numberofholes; /* In / copied out */
+
+ REAL *regionlist; /* In / pointer to array copied out */
+ int numberofregions; /* In / copied out */
+
+ int *edgelist; /* Out only */
+ int *edgemarkerlist; /* Not used with Voronoi diagram; out only */
+ REAL *normlist; /* Used only with Voronoi diagram; out only */
+ int numberofedges; /* Out only */
+};
+
+/* Data structure for command line switches and file names. This structure
+ * is used (instead of global variables) to allow reentrancy.
+
+ * Switches for the triangulator.
+ * poly: -p switch.
+ * refine: -r switch.
+ * quality: -q switch.
+ * minangle: minimum angle bound, specified after -q switch.
+ * goodangle: cosine squared of minangle.
+ * offconstant: constant used to place off-center Steiner points.
+ * vararea: -a switch without number.
+ * fixedarea: -a switch with number.
+ * maxarea: maximum area bound, specified after -a switch.
+ * usertest: -u switch.
+ * regionattrib: -A switch.
+ * convex: -c switch.
+ * weighted: 1 for -w switch, 2 for -W switch.
+ * jettison: -j switch
+ * firstnumber: inverse of -z switch. All items are numbered starting
+ * from `firstnumber'.
+ * edgesout: -e switch.
+ * voronoi: -v switch.
+ * neighbors: -n switch.
+ * geomview: -g switch.
+ * nobound: -B switch.
+ * nopolywritten: -P switch.
+ * nonodewritten: -N switch.
+ * noelewritten: -E switch.
+ * noiterationnum: -I switch.
+ * noholes: -O switch.
+ * noexact: -X switch.
+ * order: element order, specified after -o switch.
+ * nobisect: count of how often -Y switch is selected.
+ * steiner: maximum number of Steiner points, specified after -S switch.
+ * incremental: -i switch. sweepline: -F switch.
+ * dwyer: inverse of -l switch.
+ * splitseg: -s switch.
+ * conformdel: -D switch. docheck: -C switch.
+ * quiet: -Q switch. verbose: count of how often -V switch is selected.
+ * usesegments: -p, -r, -q, or -c switch; determines whether segments are
+ * used at all.
+ *
+ * Read the instructions to find out the meaning of these switches. */
+
+typedef struct behavior TriangleOptions;
+
+struct behavior {
+ int poly, refine, quality, vararea, fixedarea, usertest;
+ int regionattrib, convex, weighted, jettison;
+ int firstnumber;
+ int edgesout, voronoi, neighbors, geomview;
+ int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum;
+ int noholes, noexact, conformdel;
+ int incremental, sweepline, dwyer;
+ int splitseg;
+ int docheck;
+ int quiet, verbose;
+ int usesegments;
+ int order;
+ int nobisect;
+ int steiner;REAL minangle, goodangle, offconstant;REAL maxarea;
+
+};
+void parsecommandline(int argc, char **argv, struct behavior *b);
+void triangulate(struct behavior *, struct triangulateio *, struct triangulateio *,
+ struct triangulateio *);
+
diff --git a/vtm/jni/triangle/triangle_dbg.c b/vtm/jni/triangle/triangle_dbg.c
new file mode 100644
index 00000000..f6374ba3
--- /dev/null
+++ b/vtm/jni/triangle/triangle_dbg.c
@@ -0,0 +1,441 @@
+#include "triangle_private.h"
+
+/*****************************************************************************/
+/* */
+/* quality_statistics() Print statistics about the quality of the mesh. */
+/* */
+/*****************************************************************************/
+
+void quality_statistics(struct mesh *m, struct behavior *b) {
+ struct otri triangleloop;
+ vertex p[3];
+ REAL cossquaretable[8];
+ REAL ratiotable[16];
+ REAL dx[3], dy[3];
+ REAL edgelength[3];
+ REAL dotproduct;
+ REAL cossquare;
+ REAL triarea;
+ REAL shortest, longest;
+ REAL trilongest2;
+ REAL smallestarea, biggestarea;
+ REAL triminaltitude2;
+ REAL minaltitude;
+ REAL triaspect2;
+ REAL worstaspect;
+ REAL smallestangle, biggestangle;
+ REAL radconst, degconst;
+ int angletable[18];
+ int aspecttable[16];
+ int aspectindex;
+ int tendegree;
+ int acutebiggest;
+ int i, ii, j, k;
+
+ printf("Mesh quality statistics:\n\n");
+ radconst = PI / 18.0;
+ degconst = 180.0 / PI;
+ for (i = 0; i < 8; i++) {
+ cossquaretable[i] = cos(radconst * (REAL) (i + 1));
+ cossquaretable[i] = cossquaretable[i] * cossquaretable[i];
+ }
+ for (i = 0; i < 18; i++) {
+ angletable[i] = 0;
+ }
+
+ ratiotable[0] = 1.5;
+ ratiotable[1] = 2.0;
+ ratiotable[2] = 2.5;
+ ratiotable[3] = 3.0;
+ ratiotable[4] = 4.0;
+ ratiotable[5] = 6.0;
+ ratiotable[6] = 10.0;
+ ratiotable[7] = 15.0;
+ ratiotable[8] = 25.0;
+ ratiotable[9] = 50.0;
+ ratiotable[10] = 100.0;
+ ratiotable[11] = 300.0;
+ ratiotable[12] = 1000.0;
+ ratiotable[13] = 10000.0;
+ ratiotable[14] = 100000.0;
+ ratiotable[15] = 0.0;
+ for (i = 0; i < 16; i++) {
+ aspecttable[i] = 0;
+ }
+
+ worstaspect = 0.0;
+ minaltitude = m->xmax - m->xmin + m->ymax - m->ymin;
+ minaltitude = minaltitude * minaltitude;
+ shortest = minaltitude;
+ longest = 0.0;
+ smallestarea = minaltitude;
+ biggestarea = 0.0;
+ worstaspect = 0.0;
+ smallestangle = 0.0;
+ biggestangle = 2.0;
+ acutebiggest = 1;
+
+ traversalinit(&m->triangles);
+ triangleloop.tri = triangletraverse(m);
+ triangleloop.orient = 0;
+ while (triangleloop.tri != (triangle *) NULL) {
+ org(triangleloop, p[0]);
+ dest(triangleloop, p[1]);
+ apex(triangleloop, p[2]);
+ trilongest2 = 0.0;
+
+ for (i = 0; i < 3; i++) {
+ j = plus1mod3[i];
+ k = minus1mod3[i];
+ dx[i] = p[j][0] - p[k][0];
+ dy[i] = p[j][1] - p[k][1];
+ edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i];
+ if (edgelength[i] > trilongest2) {
+ trilongest2 = edgelength[i];
+ }
+ if (edgelength[i] > longest) {
+ longest = edgelength[i];
+ }
+ if (edgelength[i] < shortest) {
+ shortest = edgelength[i];
+ }
+ }
+
+ triarea = counterclockwise(m, b, p[0], p[1], p[2]);
+ if (triarea < smallestarea) {
+ smallestarea = triarea;
+ }
+ if (triarea > biggestarea) {
+ biggestarea = triarea;
+ }
+ triminaltitude2 = triarea * triarea / trilongest2;
+ if (triminaltitude2 < minaltitude) {
+ minaltitude = triminaltitude2;
+ }
+ triaspect2 = trilongest2 / triminaltitude2;
+ if (triaspect2 > worstaspect) {
+ worstaspect = triaspect2;
+ }
+ aspectindex = 0;
+ while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) && (aspectindex < 15)) {
+ aspectindex++;
+ }
+ aspecttable[aspectindex]++;
+
+ for (i = 0; i < 3; i++) {
+ j = plus1mod3[i];
+ k = minus1mod3[i];
+ dotproduct = dx[j] * dx[k] + dy[j] * dy[k];
+ cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]);
+ tendegree = 8;
+ for (ii = 7; ii >= 0; ii--) {
+ if (cossquare > cossquaretable[ii]) {
+ tendegree = ii;
+ }
+ }
+ if (dotproduct <= 0.0) {
+ angletable[tendegree]++;
+ if (cossquare > smallestangle) {
+ smallestangle = cossquare;
+ }
+ if (acutebiggest && (cossquare < biggestangle)) {
+ biggestangle = cossquare;
+ }
+ }
+ else {
+ angletable[17 - tendegree]++;
+ if (acutebiggest || (cossquare > biggestangle)) {
+ biggestangle = cossquare;
+ acutebiggest = 0;
+ }
+ }
+ }
+ triangleloop.tri = triangletraverse(m);
+ }
+
+ shortest = sqrt(shortest);
+ longest = sqrt(longest);
+ minaltitude = sqrt(minaltitude);
+ worstaspect = sqrt(worstaspect);
+ smallestarea *= 0.5;
+ biggestarea *= 0.5;
+ if (smallestangle >= 1.0) {
+ smallestangle = 0.0;
+ }
+ else {
+ smallestangle = degconst * acos(sqrt(smallestangle));
+ }
+ if (biggestangle >= 1.0) {
+ biggestangle = 180.0;
+ }
+ else {
+ if (acutebiggest) {
+ biggestangle = degconst * acos(sqrt(biggestangle));
+ }
+ else {
+ biggestangle = 180.0 - degconst * acos(sqrt(biggestangle));
+ }
+ }
+
+ printf(" Smallest area: %16.5g | Largest area: %16.5g\n", smallestarea, biggestarea);
+ printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", shortest, longest);
+ printf(
+ " Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", minaltitude, worstaspect);
+
+ printf(" Triangle aspect ratio histogram:\n");
+ printf(
+ " 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], aspecttable[8]);
+ for (i = 1; i < 7; i++) {
+ printf(
+ " %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", ratiotable[i - 1], ratiotable[i], aspecttable[i], ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]);
+ }
+ printf(
+ " %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], aspecttable[15]);
+ printf(" (Aspect ratio is longest edge divided by shortest altitude)\n\n");
+
+ printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", smallestangle, biggestangle);
+
+ printf(" Angle histogram:\n");
+ for (i = 0; i < 9; i++) {
+ printf(
+ " %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", i * 10, i * 10 + 10, angletable[i], i * 10 + 90, i * 10 + 100, angletable[i + 9]);
+ }
+ printf("\n");
+}
+
+/*****************************************************************************/
+/* */
+/* statistics() Print all sorts of cool facts. */
+/* */
+/*****************************************************************************/
+
+void statistics(struct mesh *m, struct behavior *b) {
+ printf("\nStatistics:\n\n");
+ printf(" Input vertices: %d\n", m->invertices);
+ if (b->refine) {
+ printf(" Input triangles: %d\n", m->inelements);
+ }
+ if (b->poly) {
+ printf(" Input segments: %d\n", m->insegments);
+ if (!b->refine) {
+ printf(" Input holes: %d\n", m->holes);
+ }
+ }
+
+ printf("\n Mesh vertices: %ld\n", m->vertices.items - m->undeads);
+ printf(" Mesh triangles: %ld\n", m->triangles.items);
+ printf(" Mesh edges: %ld\n", m->edges);
+ printf(" Mesh exterior boundary edges: %ld\n", m->hullsize);
+ if (b->poly || b->refine) {
+ printf(" Mesh interior boundary edges: %ld\n", m->subsegs.items - m->hullsize);
+ printf(" Mesh subsegments (constrained edges): %ld\n", m->subsegs.items);
+ }
+ printf("\n");
+
+ if (b->verbose) {
+ quality_statistics(m, b);
+ printf("Memory allocation statistics:\n\n");
+ printf(" Maximum number of vertices: %ld\n", m->vertices.maxitems);
+ printf(" Maximum number of triangles: %ld\n", m->triangles.maxitems);
+ if (m->subsegs.maxitems > 0) {
+ printf(" Maximum number of subsegments: %ld\n", m->subsegs.maxitems);
+ }
+ if (m->viri.maxitems > 0) {
+ printf(" Maximum number of viri: %ld\n", m->viri.maxitems);
+ }
+ if (m->badsubsegs.maxitems > 0) {
+ printf(" Maximum number of encroached subsegments: %ld\n", m->badsubsegs.maxitems);
+ }
+ if (m->badtriangles.maxitems > 0) {
+ printf(" Maximum number of bad triangles: %ld\n", m->badtriangles.maxitems);
+ }
+ if (m->flipstackers.maxitems > 0) {
+ printf(" Maximum number of stacked triangle flips: %ld\n", m->flipstackers.maxitems);
+ }
+ if (m->splaynodes.maxitems > 0) {
+ printf(" Maximum number of splay tree nodes: %ld\n", m->splaynodes.maxitems);
+ }
+ printf(
+ " Approximate heap memory use (bytes): %ld\n\n", m->vertices.maxitems * m->vertices.itembytes + m->triangles.maxitems * m->triangles.itembytes + m->subsegs.maxitems * m->subsegs.itembytes + m->viri.maxitems * m->viri.itembytes + m->badsubsegs.maxitems * m->badsubsegs.itembytes + m->badtriangles.maxitems * m->badtriangles.itembytes + m->flipstackers.maxitems * m->flipstackers.itembytes + m->splaynodes.maxitems * m->splaynodes.itembytes);
+
+ printf("Algorithmic statistics:\n\n");
+ if (!b->weighted) {
+ printf(" Number of incircle tests: %ld\n", m->incirclecount);
+ }
+ else {
+ printf(" Number of 3D orientation tests: %ld\n", m->orient3dcount);
+ }
+ printf(" Number of 2D orientation tests: %ld\n", m->counterclockcount);
+ if (m->hyperbolacount > 0) {
+ printf(" Number of right-of-hyperbola tests: %ld\n", m->hyperbolacount);
+ }
+ if (m->circletopcount > 0) {
+ printf(" Number of circle top computations: %ld\n", m->circletopcount);
+ }
+ if (m->circumcentercount > 0) {
+ printf(" Number of triangle circumcenter computations: %ld\n", m->circumcentercount);
+ }
+ printf("\n");
+ }
+}
+
+/********* Debugging routines begin here *********/
+/** **/
+/** **/
+
+/*****************************************************************************/
+/* */
+/* printtriangle() Print out the details of an oriented triangle. */
+/* */
+/* I originally wrote this procedure to simplify debugging; it can be */
+/* called directly from the debugger, and presents information about an */
+/* oriented triangle in digestible form. It's also used when the */
+/* highest level of verbosity (`-VVV') is specified. */
+/* */
+/*****************************************************************************/
+
+void printtriangle(struct mesh *m, struct behavior *b, struct otri *t) {
+ struct otri printtri;
+ struct osub printsh;
+ vertex printvertex;
+
+ printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, t->orient);
+ decode(t->tri[0], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [0] = Outer space\n");
+ }
+ else {
+ printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+ decode(t->tri[1], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [1] = Outer space\n");
+ }
+ else {
+ printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+ decode(t->tri[2], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [2] = Outer space\n");
+ }
+ else {
+ printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+
+ org(*t, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3);
+ else
+ printf(
+ " Origin[%d] = x%lx (%.12g, %.12g)\n", (t->orient + 1) % 3 + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ dest(*t, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3);
+ else
+ printf(
+ " Dest [%d] = x%lx (%.12g, %.12g)\n", (t->orient + 2) % 3 + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ apex(*t, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Apex [%d] = NULL\n", t->orient + 3);
+ else
+ printf(
+ " Apex [%d] = x%lx (%.12g, %.12g)\n", t->orient + 3, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+
+ if (b->usesegments) {
+ sdecode(t->tri[6], printsh);
+ if (printsh.ss != m->dummysub) {
+ printf(" [6] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ sdecode(t->tri[7], printsh);
+ if (printsh.ss != m->dummysub) {
+ printf(" [7] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ sdecode(t->tri[8], printsh);
+ if (printsh.ss != m->dummysub) {
+ printf(" [8] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ }
+
+ if (b->vararea) {
+ printf(" Area constraint: %.4g\n", areabound(*t));
+ }
+}
+
+/*****************************************************************************/
+/* */
+/* printsubseg() Print out the details of an oriented subsegment. */
+/* */
+/* I originally wrote this procedure to simplify debugging; it can be */
+/* called directly from the debugger, and presents information about an */
+/* oriented subsegment in digestible form. It's also used when the highest */
+/* level of verbosity (`-VVV') is specified. */
+/* */
+/*****************************************************************************/
+
+void printsubseg(struct mesh *m, struct behavior *b, struct osub *s) {
+ struct osub printsh;
+ struct otri printtri;
+ vertex printvertex;
+
+ printf(
+ "subsegment x%lx with orientation %d and mark %d:\n", (unsigned long) s->ss, s->ssorient, mark(*s));
+ sdecode(s->ss[0], printsh);
+ if (printsh.ss == m->dummysub) {
+ printf(" [0] = No subsegment\n");
+ }
+ else {
+ printf(" [0] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+ sdecode(s->ss[1], printsh);
+ if (printsh.ss == m->dummysub) {
+ printf(" [1] = No subsegment\n");
+ }
+ else {
+ printf(" [1] = x%lx %d\n", (unsigned long) printsh.ss, printsh.ssorient);
+ }
+
+ sorg(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Origin[%d] = NULL\n", 2 + s->ssorient);
+ else
+ printf(
+ " Origin[%d] = x%lx (%.12g, %.12g)\n", 2 + s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ sdest(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Dest [%d] = NULL\n", 3 - s->ssorient);
+ else
+ printf(
+ " Dest [%d] = x%lx (%.12g, %.12g)\n", 3 - s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+
+ decode(s->ss[6], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [6] = Outer space\n");
+ }
+ else {
+ printf(" [6] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+ decode(s->ss[7], printtri);
+ if (printtri.tri == m->dummytri) {
+ printf(" [7] = Outer space\n");
+ }
+ else {
+ printf(" [7] = x%lx %d\n", (unsigned long) printtri.tri, printtri.orient);
+ }
+
+ segorg(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Segment origin[%d] = NULL\n", 4 + s->ssorient);
+ else
+ printf(
+ " Segment origin[%d] = x%lx (%.12g, %.12g)\n", 4 + s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+ segdest(*s, printvertex);
+ if (printvertex == (vertex) NULL)
+ printf(" Segment dest [%d] = NULL\n", 5 - s->ssorient);
+ else
+ printf(
+ " Segment dest [%d] = x%lx (%.12g, %.12g)\n", 5 - s->ssorient, (unsigned long) printvertex, printvertex[0], printvertex[1]);
+}
+
+/** **/
+/** **/
+/********* Debugging routines end here *********/
diff --git a/vtm/jni/triangle/triangle_private.h b/vtm/jni/triangle/triangle_private.h
new file mode 100644
index 00000000..22d1667e
--- /dev/null
+++ b/vtm/jni/triangle/triangle_private.h
@@ -0,0 +1,1070 @@
+/* For single precision (which will save some memory and reduce paging), */
+/* define the symbol SINGLE by using the -DSINGLE compiler switch or by */
+/* writing "#define SINGLE" below. */
+/* */
+/* For double precision (which will allow you to refine meshes to a smaller */
+/* edge length), leave SINGLE undefined. */
+/* */
+/* Double precision uses more memory, but improves the resolution of the */
+/* meshes you can generate with Triangle. It also reduces the likelihood */
+/* of a floating exception due to overflow. Finally, it is much faster */
+/* than single precision on 64-bit architectures like the DEC Alpha. I */
+/* recommend double precision unless you want to generate a mesh for which */
+/* you do not have enough memory. */
+
+/* #define SINGLE */
+
+/* #ifdef SINGLE */
+/* #define REAL float */
+/* #else /\* not SINGLE *\/ */
+/* #define REAL double */
+/* #endif /\* not SINGLE *\/ */
+
+/* If yours is not a Unix system, define the NO_TIMER compiler switch to */
+/* remove the Unix-specific timing code. */
+
+/* #define NO_TIMER */
+
+/* To insert lots of self-checks for internal errors, define the SELF_CHECK */
+/* symbol. This will slow down the program significantly. It is best to */
+/* define the symbol using the -DSELF_CHECK compiler switch, but you could */
+/* write "#define SELF_CHECK" below. If you are modifying this code, I */
+/* recommend you turn self-checks on until your work is debugged. */
+
+/* #define SELF_CHECK */
+
+/* To compile Triangle as a callable object library (triangle.o), define the */
+/* TRILIBRARY symbol. Read the file triangle.h for details on how to call */
+/* the procedure triangulate() that results. */
+
+/* #define TRILIBRARY */
+
+/* It is possible to generate a smaller version of Triangle using one or */
+/* both of the following symbols. Define the REDUCED symbol to eliminate */
+/* all features that are primarily of research interest; specifically, the */
+/* -i, -F, -s, and -C switches. Define the CDT_ONLY symbol to eliminate */
+/* all meshing algorithms above and beyond constrained Delaunay */
+/* triangulation; specifically, the -r, -q, -a, -u, -D, -S, and -s */
+/* switches. These reductions are most likely to be useful when */
+/* generating an object library (triangle.o) by defining the TRILIBRARY */
+/* symbol. */
+
+/* #define REDUCED */
+/* #define CDT_ONLY */
+
+/* On some machines, my exact arithmetic routines might be defeated by the */
+/* use of internal extended precision floating-point registers. The best */
+/* way to solve this problem is to set the floating-point registers to use */
+/* single or double precision internally. On 80x86 processors, this may */
+/* be accomplished by setting the CPU86 symbol for the Microsoft C */
+/* compiler, or the LINUX symbol for the gcc compiler running on Linux. */
+/* */
+/* An inferior solution is to declare certain values as `volatile', thus */
+/* forcing them to be stored to memory and rounded off. Unfortunately, */
+/* this solution might slow Triangle down quite a bit. To use volatile */
+/* values, write "#define volatile" below. Normally, however, */
+/* should be defined to be nothing. ("#define ".) */
+/* */
+/* For more discussion, see http://www.cs.cmu.edu/~quake/robust.pc.html . */
+/* For yet more discussion, see Section 5 of my paper, "Adaptive Precision */
+/* Floating-Point Arithmetic and Fast Robust Geometric Predicates" (also */
+/* available as Section 6.6 of my dissertation). */
+
+/* #define CPU86 */
+/* #define LINUX */
+
+//#define /* Nothing */
+/* #define volatile */
+
+/* Maximum number of characters in a file name (including the null). */
+
+#define FILENAMESIZE 2048
+
+/* Maximum number of characters in a line read from a file (including the */
+/* null). */
+
+#define INPUTLINESIZE 1024
+
+/* For efficiency, a variety of data structures are allocated in bulk. The */
+/* following constants determine how many of each structure is allocated */
+/* at once. */
+
+#define TRIPERBLOCK 4092 /* Number of triangles allocated at once. */
+#define SUBSEGPERBLOCK 508 /* Number of subsegments allocated at once. */
+#define VERTEXPERBLOCK 4092 /* Number of vertices allocated at once. */
+#define VIRUSPERBLOCK 1020 /* Number of virus triangles allocated at once. */
+/* Number of encroached subsegments allocated at once. */
+#define BADSUBSEGPERBLOCK 252
+/* Number of skinny triangles allocated at once. */
+#define BADTRIPERBLOCK 4092
+/* Number of flipped triangles allocated at once. */
+#define FLIPSTACKERPERBLOCK 252
+/* Number of splay tree nodes allocated at once. */
+#define SPLAYNODEPERBLOCK 508
+
+/* The vertex types. A DEADVERTEX has been deleted entirely. An */
+/* UNDEADVERTEX is not part of the mesh, but is written to the output */
+/* .node file and affects the node indexing in the other output files. */
+
+#define INPUTVERTEX 0
+#define SEGMENTVERTEX 1
+#define FREEVERTEX 2
+#define DEADVERTEX -32768
+#define UNDEADVERTEX -32767
+
+/* The next line is used to outsmart some very stupid compilers. If your */
+/* compiler is smarter, feel free to replace the "int" with "void". */
+/* Not that it matters. */
+
+//#define VOID int
+#define VOID void
+
+/* Two constants for algorithms based on random sampling. Both constants */
+/* have been chosen empirically to optimize their respective algorithms. */
+
+/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide */
+/* how large a random sample of triangles to inspect. */
+
+#define SAMPLEFACTOR 11
+
+/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */
+/* of boundary edges should be maintained in the splay tree for point */
+/* location on the front. */
+
+/* A number that speaks for itself, every kissable digit. */
+
+#define PI 3.141592653589793238462643383279502884197169399375105820974944592308
+
+/* Another fave. */
+
+#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732
+
+/* And here's one for those of you who are intimidated by math. */
+
+#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333
+
+#include
+#include
+#include
+#include
+#ifndef NO_TIMER
+#include
+#endif /* not NO_TIMER */
+#ifdef CPU86
+#include
+#endif /* CPU86 */
+#ifdef LINUX
+#include
+#endif /* LINUX */
+#include "triangle.h"
+
+#ifdef __ANDROID__
+#include
+#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "Triangle", __VA_ARGS__)
+#endif
+
+
+/* A few forward declarations. */
+
+/* Labels that signify the result of point location. The result of a */
+/* search indicates that the point falls in the interior of a triangle, on */
+/* an edge, on a vertex, or outside the mesh. */
+
+enum locateresult {
+ INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE
+};
+
+/* Labels that signify the result of vertex insertion. The result indicates */
+/* that the vertex was inserted with complete success, was inserted but */
+/* encroaches upon a subsegment, was not inserted because it lies on a */
+/* segment, or was not inserted because another vertex occupies the same */
+/* location. */
+
+enum insertvertexresult {
+ SUCCESSFULVERTEX, ENCROACHINGVERTEX, VIOLATINGVERTEX, DUPLICATEVERTEX
+};
+
+/* Labels that signify the result of direction finding. The result */
+/* indicates that a segment connecting the two query points falls within */
+/* the direction triangle, along the left edge of the direction triangle, */
+/* or along the right edge of the direction triangle. */
+
+enum finddirectionresult {
+ WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR
+};
+/*****************************************************************************/
+/* */
+/* The basic mesh data structures */
+/* */
+/* There are three: vertices, triangles, and subsegments (abbreviated */
+/* `subseg'). These three data structures, linked by pointers, comprise */
+/* the mesh. A vertex simply represents a mesh vertex and its properties. */
+/* A triangle is a triangle. A subsegment is a special data structure used */
+/* to represent an impenetrable edge of the mesh (perhaps on the outer */
+/* boundary, on the boundary of a hole, or part of an internal boundary */
+/* separating two triangulated regions). Subsegments represent boundaries, */
+/* defined by the user, that triangles may not lie across. */
+/* */
+/* A triangle consists of a list of three vertices, a list of three */
+/* adjoining triangles, a list of three adjoining subsegments (when */
+/* segments exist), an arbitrary number of optional user-defined */
+/* floating-point attributes, and an optional area constraint. The latter */
+/* is an upper bound on the permissible area of each triangle in a region, */
+/* used for mesh refinement. */
+/* */
+/* For a triangle on a boundary of the mesh, some or all of the neighboring */
+/* triangles may not be present. For a triangle in the interior of the */
+/* mesh, often no neighboring subsegments are present. Such absent */
+/* triangles and subsegments are never represented by NULL pointers; they */
+/* are represented by two special records: `dummytri', the triangle that */
+/* fills "outer space", and `dummysub', the omnipresent subsegment. */
+/* `dummytri' and `dummysub' are used for several reasons; for instance, */
+/* they can be dereferenced and their contents examined without violating */
+/* protected memory. */
+/* */
+/* However, it is important to understand that a triangle includes other */
+/* information as well. The pointers to adjoining vertices, triangles, and */
+/* subsegments are ordered in a way that indicates their geometric relation */
+/* to each other. Furthermore, each of these pointers contains orientation */
+/* information. Each pointer to an adjoining triangle indicates which face */
+/* of that triangle is contacted. Similarly, each pointer to an adjoining */
+/* subsegment indicates which side of that subsegment is contacted, and how */
+/* the subsegment is oriented relative to the triangle. */
+/* */
+/* The data structure representing a subsegment may be thought to be */
+/* abutting the edge of one or two triangle data structures: either */
+/* sandwiched between two triangles, or resting against one triangle on an */
+/* exterior boundary or hole boundary. */
+/* */
+/* A subsegment consists of a list of four vertices--the vertices of the */
+/* subsegment, and the vertices of the segment it is a part of--a list of */
+/* two adjoining subsegments, and a list of two adjoining triangles. One */
+/* of the two adjoining triangles may not be present (though there should */
+/* always be one), and neighboring subsegments might not be present. */
+/* Subsegments also store a user-defined integer "boundary marker". */
+/* Typically, this integer is used to indicate what boundary conditions are */
+/* to be applied at that location in a finite element simulation. */
+/* */
+/* Like triangles, subsegments maintain information about the relative */
+/* orientation of neighboring objects. */
+/* */
+/* Vertices are relatively simple. A vertex is a list of floating-point */
+/* numbers, starting with the x, and y coordinates, followed by an */
+/* arbitrary number of optional user-defined floating-point attributes, */
+/* followed by an integer boundary marker. During the segment insertion */
+/* phase, there is also a pointer from each vertex to a triangle that may */
+/* contain it. Each pointer is not always correct, but when one is, it */
+/* speeds up segment insertion. These pointers are assigned values once */
+/* at the beginning of the segment insertion phase, and are not used or */
+/* updated except during this phase. Edge flipping during segment */
+/* insertion will render some of them incorrect. Hence, don't rely upon */
+/* them for anything. */
+/* */
+/* Other than the exception mentioned above, vertices have no information */
+/* about what triangles, subfacets, or subsegments they are linked to. */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* */
+/* Handles */
+/* */
+/* The oriented triangle (`otri') and oriented subsegment (`osub') data */
+/* structures defined below do not themselves store any part of the mesh. */
+/* The mesh itself is made of `triangle's, `subseg's, and `vertex's. */
+/* */
+/* Oriented triangles and oriented subsegments will usually be referred to */
+/* as "handles." A handle is essentially a pointer into the mesh; it */
+/* allows you to "hold" one particular part of the mesh. Handles are used */
+/* to specify the regions in which one is traversing and modifying the mesh.*/
+/* A single `triangle' may be held by many handles, or none at all. (The */
+/* latter case is not a memory leak, because the triangle is still */
+/* connected to other triangles in the mesh.) */
+/* */
+/* An `otri' is a handle that holds a triangle. It holds a specific edge */
+/* of the triangle. An `osub' is a handle that holds a subsegment. It */
+/* holds either the left or right side of the subsegment. */
+/* */
+/* Navigation about the mesh is accomplished through a set of mesh */
+/* manipulation primitives, further below. Many of these primitives take */
+/* a handle and produce a new handle that holds the mesh near the first */
+/* handle. Other primitives take two handles and glue the corresponding */
+/* parts of the mesh together. The orientation of the handles is */
+/* important. For instance, when two triangles are glued together by the */
+/* bond() primitive, they are glued at the edges on which the handles lie. */
+/* */
+/* Because vertices have no information about which triangles they are */
+/* attached to, I commonly represent a vertex by use of a handle whose */
+/* origin is the vertex. A single handle can simultaneously represent a */
+/* triangle, an edge, and a vertex. */
+/* */
+/*****************************************************************************/
+
+/* The triangle data structure. Each triangle contains three pointers to */
+/* adjoining triangles, plus three pointers to vertices, plus three */
+/* pointers to subsegments (declared below; these pointers are usually */
+/* `dummysub'). It may or may not also contain user-defined attributes */
+/* and/or a floating-point "area constraint." It may also contain extra */
+/* pointers for nodes, when the user asks for high-order elements. */
+/* Because the size and structure of a `triangle' is not decided until */
+/* runtime, I haven't simply declared the type `triangle' as a struct. */
+
+typedef REAL **triangle; /* Really: typedef triangle *triangle */
+
+/* An oriented triangle: includes a pointer to a triangle and orientation. */
+/* The orientation denotes an edge of the triangle. Hence, there are */
+/* three possible orientations. By convention, each edge always points */
+/* counterclockwise about the corresponding triangle. */
+
+struct otri {
+ triangle *tri;
+ int orient; /* Ranges from 0 to 2. */
+};
+
+/* The subsegment data structure. Each subsegment contains two pointers to */
+/* adjoining subsegments, plus four pointers to vertices, plus two */
+/* pointers to adjoining triangles, plus one boundary marker, plus one */
+/* segment number. */
+
+typedef REAL **subseg; /* Really: typedef subseg *subseg */
+
+/* An oriented subsegment: includes a pointer to a subsegment and an */
+/* orientation. The orientation denotes a side of the edge. Hence, there */
+/* are two possible orientations. By convention, the edge is always */
+/* directed so that the "side" denoted is the right side of the edge. */
+
+struct osub {
+ subseg *ss;
+ int ssorient; /* Ranges from 0 to 1. */
+};
+
+/* The vertex data structure. Each vertex is actually an array of REALs. */
+/* The number of REALs is unknown until runtime. An integer boundary */
+/* marker, and sometimes a pointer to a triangle, is appended after the */
+/* REALs. */
+
+typedef REAL *vertex;
+
+/* A queue used to store encroached subsegments. Each subsegment's vertices */
+/* are stored so that we can check whether a subsegment is still the same. */
+
+struct badsubseg {
+ subseg encsubseg; /* An encroached subsegment. */
+ vertex subsegorg, subsegdest; /* Its two vertices. */
+};
+
+/* A queue used to store bad triangles. The key is the square of the cosine */
+/* of the smallest angle of the triangle. Each triangle's vertices are */
+/* stored so that one can check whether a triangle is still the same. */
+
+struct badtriang {
+ triangle poortri; /* A skinny or too-large triangle. */
+ REAL key; /* cos^2 of smallest (apical) angle. */
+ vertex triangorg, triangdest, triangapex; /* Its three vertices. */
+ struct badtriang *nexttriang; /* Pointer to next bad triangle. */
+};
+
+/* A stack of triangles flipped during the most recent vertex insertion. */
+/* The stack is used to undo the vertex insertion if the vertex encroaches */
+/* upon a subsegment. */
+
+struct flipstacker {
+ triangle flippedtri; /* A recently flipped triangle. */
+ struct flipstacker *prevflip; /* Previous flip in the stack. */
+};
+
+/* A node in a heap used to store events for the sweepline Delaunay */
+/* algorithm. Nodes do not point directly to their parents or children in */
+/* the heap. Instead, each node knows its position in the heap, and can */
+/* look up its parent and children in a separate array. The `eventptr' */
+/* points either to a `vertex' or to a triangle (in encoded format, so */
+/* that an orientation is included). In the latter case, the origin of */
+/* the oriented triangle is the apex of a "circle event" of the sweepline */
+/* algorithm. To distinguish site events from circle events, all circle */
+/* events are given an invalid (smaller than `xmin') x-coordinate `xkey'. */
+
+struct event {
+ REAL xkey, ykey; /* Coordinates of the event. */
+ VOID *eventptr; /* Can be a vertex or the location of a circle event. */
+ int heapposition; /* Marks this event's position in the heap. */
+};
+
+/* A node in the splay tree. Each node holds an oriented ghost triangle */
+/* that represents a boundary edge of the growing triangulation. When a */
+/* circle event covers two boundary edges with a triangle, so that they */
+/* are no longer boundary edges, those edges are not immediately deleted */
+/* from the tree; rather, they are lazily deleted when they are next */
+/* encountered. (Since only a random sample of boundary edges are kept */
+/* in the tree, lazy deletion is faster.) `keydest' is used to verify */
+/* that a triangle is still the same as when it entered the splay tree; if */
+/* it has been rotated (due to a circle event), it no longer represents a */
+/* boundary edge and should be deleted. */
+
+struct splaynode {
+ struct otri keyedge; /* Lprev of an edge on the front. */
+ vertex keydest; /* Used to verify that splay node is still live. */
+ struct splaynode *lchild, *rchild; /* Children in splay tree. */
+};
+
+/* A type used to allocate memory. firstblock is the first block of items. */
+/* nowblock is the block from which items are currently being allocated. */
+/* nextitem points to the next slab of free memory for an item. */
+/* deaditemstack is the head of a linked list (stack) of deallocated items */
+/* that can be recycled. unallocateditems is the number of items that */
+/* remain to be allocated from nowblock. */
+/* */
+/* Traversal is the process of walking through the entire list of items, and */
+/* is separate from allocation. Note that a traversal will visit items on */
+/* the "deaditemstack" stack as well as live items. pathblock points to */
+/* the block currently being traversed. pathitem points to the next item */
+/* to be traversed. pathitemsleft is the number of items that remain to */
+/* be traversed in pathblock. */
+/* */
+/* alignbytes determines how new records should be aligned in memory. */
+/* itembytes is the length of a record in bytes (after rounding up). */
+/* itemsperblock is the number of items allocated at once in a single */
+/* block. itemsfirstblock is the number of items in the first block, */
+/* which can vary from the others. items is the number of currently */
+/* allocated items. maxitems is the maximum number of items that have */
+/* been allocated at once; it is the current number of items plus the */
+/* number of records kept on deaditemstack. */
+
+struct memorypool {
+ VOID **firstblock, **nowblock;
+ VOID *nextitem;
+ VOID *deaditemstack;
+ VOID **pathblock;
+ VOID *pathitem;
+ int alignbytes;
+ int itembytes;
+ int itemsperblock;
+ int itemsfirstblock;
+ long items, maxitems;
+ int unallocateditems;
+ int pathitemsleft;
+};
+
+/* Global constants. */
+
+REAL splitter; /* Used to split REAL factors for exact multiplication. */
+REAL epsilon; /* Floating-point machine epsilon. */
+REAL resulterrbound;
+REAL ccwerrboundA, ccwerrboundB, ccwerrboundC;
+REAL iccerrboundA, iccerrboundB, iccerrboundC;
+REAL o3derrboundA, o3derrboundB, o3derrboundC;
+
+/* Random number seed is not constant, but I've made it global anyway. */
+
+unsigned long randomseed; /* Current random number seed. */
+
+/* Mesh data structure. Triangle operates on only one mesh, but the mesh */
+/* structure is used (instead of global variables) to allow reentrancy. */
+
+struct mesh {
+
+ /* Variables used to allocate memory for triangles, subsegments, vertices, */
+ /* viri (triangles being eaten), encroached segments, bad (skinny or too */
+ /* large) triangles, and splay tree nodes. */
+
+ struct memorypool triangles;
+ struct memorypool subsegs;
+ struct memorypool vertices;
+ struct memorypool viri;
+ struct memorypool badsubsegs;
+ struct memorypool badtriangles;
+ struct memorypool flipstackers;
+ struct memorypool splaynodes;
+
+ /* Variables that maintain the bad triangle queues. The queues are */
+ /* ordered from 4095 (highest priority) to 0 (lowest priority). */
+
+ struct badtriang *queuefront[4096];
+ struct badtriang *queuetail[4096];
+ int nextnonemptyq[4096];
+ int firstnonemptyq;
+
+ /* Variable that maintains the stack of recently flipped triangles. */
+
+ struct flipstacker *lastflip;
+
+ /* Other variables. */
+
+ REAL xmin, xmax, ymin, ymax; /* x and y bounds. */
+ REAL xminextreme; /* Nonexistent x value used as a flag in sweepline. */
+ int invertices; /* Number of input vertices. */
+ int inelements; /* Number of input triangles. */
+ int insegments; /* Number of input segments. */
+ int holes; /* Number of input holes. */
+ int regions; /* Number of input regions. */
+ int undeads; /* Number of input vertices that don't appear in the mesh. */
+ long edges; /* Number of output edges. */
+ int mesh_dim; /* Dimension (ought to be 2). */
+ int nextras; /* Number of attributes per vertex. */
+ int eextras; /* Number of attributes per triangle. */
+ long hullsize; /* Number of edges in convex hull. */
+ int steinerleft; /* Number of Steiner points not yet used. */
+ int vertexmarkindex; /* Index to find boundary marker of a vertex. */
+ int vertex2triindex; /* Index to find a triangle adjacent to a vertex. */
+ int highorderindex; /* Index to find extra nodes for high-order elements. */
+ int elemattribindex; /* Index to find attributes of a triangle. */
+ int areaboundindex; /* Index to find area bound of a triangle. */
+ int checksegments; /* Are there segments in the triangulation yet? */
+ int checkquality; /* Has quality triangulation begun yet? */
+ int readnodefile; /* Has a .node file been read? */
+ long samples; /* Number of random samples for point location. */
+
+ long incirclecount; /* Number of incircle tests performed. */
+ long counterclockcount; /* Number of counterclockwise tests performed. */
+ long orient3dcount; /* Number of 3D orientation tests performed. */
+ long hyperbolacount; /* Number of right-of-hyperbola tests performed. */
+ long circumcentercount; /* Number of circumcenter calculations performed. */
+ long circletopcount; /* Number of circle top calculations performed. */
+
+ /* Triangular bounding box vertices. */
+
+ vertex infvertex1, infvertex2, infvertex3;
+
+ /* Pointer to the `triangle' that occupies all of "outer space." */
+
+ triangle *dummytri;
+ triangle *dummytribase; /* Keep base address so we can free() it later. */
+
+ /* Pointer to the omnipresent subsegment. Referenced by any triangle or */
+ /* subsegment that isn't really connected to a subsegment at that */
+ /* location. */
+
+ subseg *dummysub;
+ subseg *dummysubbase; /* Keep base address so we can free() it later. */
+
+ /* Pointer to a recently visited triangle. Improves point location if */
+ /* proximate vertices are inserted sequentially. */
+
+ struct otri recenttri;
+
+};
+/* End of `struct mesh'. */
+
+
+
+/*****************************************************************************/
+/* */
+/* Mesh manipulation primitives. Each triangle contains three pointers to */
+/* other triangles, with orientations. Each pointer points not to the */
+/* first byte of a triangle, but to one of the first three bytes of a */
+/* triangle. It is necessary to extract both the triangle itself and the */
+/* orientation. To save memory, I keep both pieces of information in one */
+/* pointer. To make this possible, I assume that all triangles are aligned */
+/* to four-byte boundaries. The decode() routine below decodes a pointer, */
+/* extracting an orientation (in the range 0 to 2) and a pointer to the */
+/* beginning of a triangle. The encode() routine compresses a pointer to a */
+/* triangle and an orientation into a single pointer. My assumptions that */
+/* triangles are four-byte-aligned and that the `unsigned long' type is */
+/* long enough to hold a pointer are two of the few kludges in this program.*/
+/* */
+/* Subsegments are manipulated similarly. A pointer to a subsegment */
+/* carries both an address and an orientation in the range 0 to 1. */
+/* */
+/* The other primitives take an oriented triangle or oriented subsegment, */
+/* and return an oriented triangle or oriented subsegment or vertex; or */
+/* they change the connections in the data structure. */
+/* */
+/* Below, triangles and subsegments are denoted by their vertices. The */
+/* triangle abc has origin (org) a, destination (dest) b, and apex (apex) */
+/* c. These vertices occur in counterclockwise order about the triangle. */
+/* The handle abc may simultaneously denote vertex a, edge ab, and triangle */
+/* abc. */
+/* */
+/* Similarly, the subsegment ab has origin (sorg) a and destination (sdest) */
+/* b. If ab is thought to be directed upward (with b directly above a), */
+/* then the handle ab is thought to grasp the right side of ab, and may */
+/* simultaneously denote vertex a and edge ab. */
+/* */
+/* An asterisk (*) denotes a vertex whose identity is unknown. */
+/* */
+/* Given this notation, a partial list of mesh manipulation primitives */
+/* follows. */
+/* */
+/* */
+/* For triangles: */
+/* */
+/* sym: Find the abutting triangle; same edge. */
+/* sym(abc) -> ba* */
+/* */
+/* lnext: Find the next edge (counterclockwise) of a triangle. */
+/* lnext(abc) -> bca */
+/* */
+/* lprev: Find the previous edge (clockwise) of a triangle. */
+/* lprev(abc) -> cab */
+/* */
+/* onext: Find the next edge counterclockwise with the same origin. */
+/* onext(abc) -> ac* */
+/* */
+/* oprev: Find the next edge clockwise with the same origin. */
+/* oprev(abc) -> a*b */
+/* */
+/* dnext: Find the next edge counterclockwise with the same destination. */
+/* dnext(abc) -> *ba */
+/* */
+/* dprev: Find the next edge clockwise with the same destination. */
+/* dprev(abc) -> cb* */
+/* */
+/* rnext: Find the next edge (counterclockwise) of the adjacent triangle. */
+/* rnext(abc) -> *a* */
+/* */
+/* rprev: Find the previous edge (clockwise) of the adjacent triangle. */
+/* rprev(abc) -> b** */
+/* */
+/* org: Origin dest: Destination apex: Apex */
+/* org(abc) -> a dest(abc) -> b apex(abc) -> c */
+/* */
+/* bond: Bond two triangles together at the resepective handles. */
+/* bond(abc, bad) */
+/* */
+/* */
+/* For subsegments: */
+/* */
+/* ssym: Reverse the orientation of a subsegment. */
+/* ssym(ab) -> ba */
+/* */
+/* spivot: Find adjoining subsegment with the same origin. */
+/* spivot(ab) -> a* */
+/* */
+/* snext: Find next subsegment in sequence. */
+/* snext(ab) -> b* */
+/* */
+/* sorg: Origin sdest: Destination */
+/* sorg(ab) -> a sdest(ab) -> b */
+/* */
+/* sbond: Bond two subsegments together at the respective origins. */
+/* sbond(ab, ac) */
+/* */
+/* */
+/* For interacting tetrahedra and subfacets: */
+/* */
+/* tspivot: Find a subsegment abutting a triangle. */
+/* tspivot(abc) -> ba */
+/* */
+/* stpivot: Find a triangle abutting a subsegment. */
+/* stpivot(ab) -> ba* */
+/* */
+/* tsbond: Bond a triangle to a subsegment. */
+/* tsbond(abc, ba) */
+/* */
+/*****************************************************************************/
+
+/********* Mesh manipulation primitives begin here *********/
+/** **/
+/** **/
+
+/* Fast lookup arrays to speed some of the mesh manipulation primitives. */
+
+extern int plus1mod3[]; // = { 1, 2, 0 };
+extern int minus1mod3[]; // = { 2, 0, 1 };
+
+/********* Primitives for triangles *********/
+/* */
+/* */
+
+/* decode() converts a pointer to an oriented triangle. The orientation is */
+/* extracted from the two least significant bits of the pointer. */
+
+#define decode(ptr, otri) \
+ (otri).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l); \
+ (otri).tri = (triangle *) \
+ ((unsigned long) (ptr) ^ (unsigned long) (otri).orient)
+
+/* encode() compresses an oriented triangle into a single pointer. It */
+/* relies on the assumption that all triangles are aligned to four-byte */
+/* boundaries, so the two least significant bits of (otri).tri are zero. */
+
+#define encode(otri) \
+ (triangle) ((unsigned long) (otri).tri | (unsigned long) (otri).orient)
+
+/* The following handle manipulation primitives are all described by Guibas */
+/* and Stolfi. However, Guibas and Stolfi use an edge-based data */
+/* structure, whereas I use a triangle-based data structure. */
+
+/* sym() finds the abutting triangle, on the same edge. Note that the edge */
+/* direction is necessarily reversed, because the handle specified by an */
+/* oriented triangle is directed counterclockwise around the triangle. */
+
+#define sym(otri1, otri2) \
+ ptr = (otri1).tri[(otri1).orient]; \
+ decode(ptr, otri2);
+
+#define symself(otri) \
+ ptr = (otri).tri[(otri).orient]; \
+ decode(ptr, otri);
+
+/* lnext() finds the next edge (counterclockwise) of a triangle. */
+
+#define lnext(otri1, otri2) \
+ (otri2).tri = (otri1).tri; \
+ (otri2).orient = plus1mod3[(otri1).orient]
+
+#define lnextself(otri) \
+ (otri).orient = plus1mod3[(otri).orient]
+
+/* lprev() finds the previous edge (clockwise) of a triangle. */
+
+#define lprev(otri1, otri2) \
+ (otri2).tri = (otri1).tri; \
+ (otri2).orient = minus1mod3[(otri1).orient]
+
+#define lprevself(otri) \
+ (otri).orient = minus1mod3[(otri).orient]
+
+/* onext() spins counterclockwise around a vertex; that is, it finds the */
+/* next edge with the same origin in the counterclockwise direction. This */
+/* edge is part of a different triangle. */
+
+#define onext(otri1, otri2) \
+ lprev(otri1, otri2); \
+ symself(otri2);
+
+#define onextself(otri) \
+ lprevself(otri); \
+ symself(otri);
+
+/* oprev() spins clockwise around a vertex; that is, it finds the next edge */
+/* with the same origin in the clockwise direction. This edge is part of */
+/* a different triangle. */
+
+#define oprev(otri1, otri2) \
+ sym(otri1, otri2); \
+ lnextself(otri2);
+
+#define oprevself(otri) \
+ symself(otri); \
+ lnextself(otri);
+
+/* dnext() spins counterclockwise around a vertex; that is, it finds the */
+/* next edge with the same destination in the counterclockwise direction. */
+/* This edge is part of a different triangle. */
+
+#define dnext(otri1, otri2) \
+ sym(otri1, otri2); \
+ lprevself(otri2);
+
+#define dnextself(otri) \
+ symself(otri); \
+ lprevself(otri);
+
+/* dprev() spins clockwise around a vertex; that is, it finds the next edge */
+/* with the same destination in the clockwise direction. This edge is */
+/* part of a different triangle. */
+
+#define dprev(otri1, otri2) \
+ lnext(otri1, otri2); \
+ symself(otri2);
+
+#define dprevself(otri) \
+ lnextself(otri); \
+ symself(otri);
+
+/* rnext() moves one edge counterclockwise about the adjacent triangle. */
+/* (It's best understood by reading Guibas and Stolfi. It involves */
+/* changing triangles twice.) */
+
+#define rnext(otri1, otri2) \
+ sym(otri1, otri2); \
+ lnextself(otri2); \
+ symself(otri2);
+
+#define rnextself(otri) \
+ symself(otri); \
+ lnextself(otri); \
+ symself(otri);
+
+/* rprev() moves one edge clockwise about the adjacent triangle. */
+/* (It's best understood by reading Guibas and Stolfi. It involves */
+/* changing triangles twice.) */
+
+#define rprev(otri1, otri2) \
+ sym(otri1, otri2); \
+ lprevself(otri2); \
+ symself(otri2);
+
+#define rprevself(otri) \
+ symself(otri); \
+ lprevself(otri); \
+ symself(otri);
+
+/* These primitives determine or set the origin, destination, or apex of a */
+/* triangle. */
+
+#define org(otri, vertexptr) \
+ vertexptr = (vertex) (otri).tri[plus1mod3[(otri).orient] + 3]
+
+#define dest(otri, vertexptr) \
+ vertexptr = (vertex) (otri).tri[minus1mod3[(otri).orient] + 3]
+
+#define apex(otri, vertexptr) \
+ vertexptr = (vertex) (otri).tri[(otri).orient + 3]
+
+#define setorg(otri, vertexptr) \
+ (otri).tri[plus1mod3[(otri).orient] + 3] = (triangle) vertexptr
+
+#define setdest(otri, vertexptr) \
+ (otri).tri[minus1mod3[(otri).orient] + 3] = (triangle) vertexptr
+
+#define setapex(otri, vertexptr) \
+ (otri).tri[(otri).orient + 3] = (triangle) vertexptr
+
+/* Bond two triangles together. */
+
+#define bond(otri1, otri2) \
+ (otri1).tri[(otri1).orient] = encode(otri2); \
+ (otri2).tri[(otri2).orient] = encode(otri1)
+
+/* Dissolve a bond (from one side). Note that the other triangle will still */
+/* think it's connected to this triangle. Usually, however, the other */
+/* triangle is being deleted entirely, or bonded to another triangle, so */
+/* it doesn't matter. */
+
+#define dissolve(otri) \
+ (otri).tri[(otri).orient] = (triangle) m->dummytri
+
+/* Copy an oriented triangle. */
+
+#define otricopy(otri1, otri2) \
+ (otri2).tri = (otri1).tri; \
+ (otri2).orient = (otri1).orient
+
+/* Test for equality of oriented triangles. */
+
+#define otriequal(otri1, otri2) \
+ (((otri1).tri == (otri2).tri) && \
+ ((otri1).orient == (otri2).orient))
+
+/* Primitives to infect or cure a triangle with the virus. These rely on */
+/* the assumption that all subsegments are aligned to four-byte boundaries.*/
+
+#define infect(otri) \
+ (otri).tri[6] = (triangle) \
+ ((unsigned long) (otri).tri[6] | (unsigned long) 2l)
+
+#define uninfect(otri) \
+ (otri).tri[6] = (triangle) \
+ ((unsigned long) (otri).tri[6] & ~ (unsigned long) 2l)
+
+/* Test a triangle for viral infection. */
+
+#define infected(otri) \
+ (((unsigned long) (otri).tri[6] & (unsigned long) 2l) != 0l)
+
+/* Check or set a triangle's attributes. */
+
+#define elemattribute(otri, attnum) \
+ ((REAL *) (otri).tri)[m->elemattribindex + (attnum)]
+
+#define setelemattribute(otri, attnum, value) \
+ ((REAL *) (otri).tri)[m->elemattribindex + (attnum)] = value
+
+/* Check or set a triangle's maximum area bound. */
+
+#define areabound(otri) ((REAL *) (otri).tri)[m->areaboundindex]
+
+#define setareabound(otri, value) \
+ ((REAL *) (otri).tri)[m->areaboundindex] = value
+
+/* Check or set a triangle's deallocation. Its second pointer is set to */
+/* NULL to indicate that it is not allocated. (Its first pointer is used */
+/* for the stack of dead items.) Its fourth pointer (its first vertex) */
+/* is set to NULL in case a `badtriang' structure points to it. */
+
+#define deadtri(tria) ((tria)[1] == (triangle) NULL)
+
+#define killtri(tria) \
+ (tria)[1] = (triangle) NULL; \
+ (tria)[3] = (triangle) NULL
+
+/********* Primitives for subsegments *********/
+/* */
+/* */
+
+/* sdecode() converts a pointer to an oriented subsegment. The orientation */
+/* is extracted from the least significant bit of the pointer. The two */
+/* least significant bits (one for orientation, one for viral infection) */
+/* are masked out to produce the real pointer. */
+
+#define sdecode(sptr, osub) \
+ (osub).ssorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l); \
+ (osub).ss = (subseg *) \
+ ((unsigned long) (sptr) & ~ (unsigned long) 3l)
+
+/* sencode() compresses an oriented subsegment into a single pointer. It */
+/* relies on the assumption that all subsegments are aligned to two-byte */
+/* boundaries, so the least significant bit of (osub).ss is zero. */
+
+#define sencode(osub) \
+ (subseg) ((unsigned long) (osub).ss | (unsigned long) (osub).ssorient)
+
+/* ssym() toggles the orientation of a subsegment. */
+
+#define ssym(osub1, osub2) \
+ (osub2).ss = (osub1).ss; \
+ (osub2).ssorient = 1 - (osub1).ssorient
+
+#define ssymself(osub) \
+ (osub).ssorient = 1 - (osub).ssorient
+
+/* spivot() finds the other subsegment (from the same segment) that shares */
+/* the same origin. */
+
+#define spivot(osub1, osub2) \
+ sptr = (osub1).ss[(osub1).ssorient]; \
+ sdecode(sptr, osub2)
+
+#define spivotself(osub) \
+ sptr = (osub).ss[(osub).ssorient]; \
+ sdecode(sptr, osub)
+
+/* snext() finds the next subsegment (from the same segment) in sequence; */
+/* one whose origin is the input subsegment's destination. */
+
+#define snext(osub1, osub2) \
+ sptr = (osub1).ss[1 - (osub1).ssorient]; \
+ sdecode(sptr, osub2)
+
+#define snextself(osub) \
+ sptr = (osub).ss[1 - (osub).ssorient]; \
+ sdecode(sptr, osub)
+
+/* These primitives determine or set the origin or destination of a */
+/* subsegment or the segment that includes it. */
+
+#define sorg(osub, vertexptr) \
+ vertexptr = (vertex) (osub).ss[2 + (osub).ssorient]
+
+#define sdest(osub, vertexptr) \
+ vertexptr = (vertex) (osub).ss[3 - (osub).ssorient]
+
+#define setsorg(osub, vertexptr) \
+ (osub).ss[2 + (osub).ssorient] = (subseg) vertexptr
+
+#define setsdest(osub, vertexptr) \
+ (osub).ss[3 - (osub).ssorient] = (subseg) vertexptr
+
+#define segorg(osub, vertexptr) \
+ vertexptr = (vertex) (osub).ss[4 + (osub).ssorient]
+
+#define segdest(osub, vertexptr) \
+ vertexptr = (vertex) (osub).ss[5 - (osub).ssorient]
+
+#define setsegorg(osub, vertexptr) \
+ (osub).ss[4 + (osub).ssorient] = (subseg) vertexptr
+
+#define setsegdest(osub, vertexptr) \
+ (osub).ss[5 - (osub).ssorient] = (subseg) vertexptr
+
+/* These primitives read or set a boundary marker. Boundary markers are */
+/* used to hold user-defined tags for setting boundary conditions in */
+/* finite element solvers. */
+
+#define mark(osub) (* (int *) ((osub).ss + 8))
+
+#define setmark(osub, value) \
+ * (int *) ((osub).ss + 8) = value
+
+/* Bond two subsegments together. */
+
+#define sbond(osub1, osub2) \
+ (osub1).ss[(osub1).ssorient] = sencode(osub2); \
+ (osub2).ss[(osub2).ssorient] = sencode(osub1)
+
+/* Dissolve a subsegment bond (from one side). Note that the other */
+/* subsegment will still think it's connected to this subsegment. */
+
+#define sdissolve(osub) \
+ (osub).ss[(osub).ssorient] = (subseg) m->dummysub
+
+/* Copy a subsegment. */
+
+#define subsegcopy(osub1, osub2) \
+ (osub2).ss = (osub1).ss; \
+ (osub2).ssorient = (osub1).ssorient
+
+/* Test for equality of subsegments. */
+
+#define subsegequal(osub1, osub2) \
+ (((osub1).ss == (osub2).ss) && \
+ ((osub1).ssorient == (osub2).ssorient))
+
+/* Check or set a subsegment's deallocation. Its second pointer is set to */
+/* NULL to indicate that it is not allocated. (Its first pointer is used */
+/* for the stack of dead items.) Its third pointer (its first vertex) */
+/* is set to NULL in case a `badsubseg' structure points to it. */
+
+#define deadsubseg(sub) ((sub)[1] == (subseg) NULL)
+
+#define killsubseg(sub) \
+ (sub)[1] = (subseg) NULL; \
+ (sub)[2] = (subseg) NULL
+
+/********* Primitives for interacting triangles and subsegments *********/
+/* */
+/* */
+
+/* tspivot() finds a subsegment abutting a triangle. */
+
+#define tspivot(otri, osub) \
+ sptr = (subseg) (otri).tri[6 + (otri).orient]; \
+ sdecode(sptr, osub)
+
+/* stpivot() finds a triangle abutting a subsegment. It requires that the */
+/* variable `ptr' of type `triangle' be defined. */
+
+#define stpivot(osub, otri) \
+ ptr = (triangle) (osub).ss[6 + (osub).ssorient]; \
+ decode(ptr, otri)
+
+/* Bond a triangle to a subsegment. */
+
+#define tsbond(otri, osub) \
+ (otri).tri[6 + (otri).orient] = (triangle) sencode(osub); \
+ (osub).ss[6 + (osub).ssorient] = (subseg) encode(otri)
+
+/* Dissolve a bond (from the triangle side). */
+
+#define tsdissolve(otri) \
+ (otri).tri[6 + (otri).orient] = (triangle) m->dummysub
+
+/* Dissolve a bond (from the subsegment side). */
+
+#define stdissolve(osub) \
+ (osub).ss[6 + (osub).ssorient] = (subseg) m->dummytri
+
+/********* Primitives for vertices *********/
+/* */
+/* */
+
+#define vertexmark(vx) ((int *) (vx))[m->vertexmarkindex]
+
+#define setvertexmark(vx, value) \
+ ((int *) (vx))[m->vertexmarkindex] = value
+
+#define vertextype(vx) ((int *) (vx))[m->vertexmarkindex + 1]
+
+#define setvertextype(vx, value) \
+ ((int *) (vx))[m->vertexmarkindex + 1] = value
+
+#define vertex2tri(vx) ((triangle *) (vx))[m->vertex2triindex]
+
+#define setvertex2tri(vx, value) \
+ ((triangle *) (vx))[m->vertex2triindex] = value
+
+/** **/
+/** **/
+/********* Mesh manipulation primitives end here *********/
+
+
+
+void printtriangle(struct mesh *m, struct behavior *b, struct otri *t);
+void printsubseg(struct mesh *m, struct behavior *b, struct osub *s);
+void quality_statistics(struct mesh *m, struct behavior *b);
+void statistics(struct mesh *m, struct behavior *b);
+// provided by triangle.c
+void traversalinit(struct memorypool *pool);
+REAL counterclockwise(struct mesh *m, struct behavior *b, vertex pa, vertex pb, vertex pc);
+triangle *triangletraverse(struct mesh *m);
diff --git a/vtm/src/org/oscim/backend/AssetAdapter.java b/vtm/src/org/oscim/backend/AssetAdapter.java
new file mode 100644
index 00000000..e9e16a59
--- /dev/null
+++ b/vtm/src/org/oscim/backend/AssetAdapter.java
@@ -0,0 +1,10 @@
+package org.oscim.backend;
+
+import java.io.InputStream;
+
+public abstract class AssetAdapter {
+ public static AssetAdapter g;
+
+ public abstract InputStream openFileAsStream(String name);
+
+}
diff --git a/vtm/src/org/oscim/backend/BitmapUtils.java b/vtm/src/org/oscim/backend/BitmapUtils.java
new file mode 100644
index 00000000..a4f87460
--- /dev/null
+++ b/vtm/src/org/oscim/backend/BitmapUtils.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2010, 2011, 2012 mapsforge.org
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program. If not, see .
+ */
+package org.oscim.backend;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.oscim.backend.canvas.Bitmap;
+
+public final class BitmapUtils {
+ // private static final String PREFIX_FILE = "file:";
+ // private static final String PREFIX_JAR = "jar:";
+ //
+ // private static InputStream createInputStream(String src) throws
+ // FileNotFoundException {
+ // if (src.startsWith(PREFIX_JAR)) {
+ // String name = "/org/oscim/theme/styles/" +
+ // src.substring(PREFIX_JAR.length());
+ //
+ // InputStream inputStream = BitmapUtils.class.getResourceAsStream(name);
+ // if (inputStream == null) {
+ // throw new FileNotFoundException("resource not found: " + src + " " +
+ // name);
+ // }
+ // return inputStream;
+ // } else if (src.startsWith(PREFIX_FILE)) {
+ // File file = new File(src.substring(PREFIX_FILE.length()));
+ // if (!file.exists()) {
+ // throw new IllegalArgumentException("file does not exist: " + src);
+ // } else if (!file.isFile()) {
+ // throw new IllegalArgumentException("not a file: " + src);
+ // } else if (!file.canRead()) {
+ // throw new IllegalArgumentException("cannot read file: " + src);
+ // }
+ // return new FileInputStream(file);
+ // }
+ // throw new IllegalArgumentException("invalid bitmap source: " + src);
+ // }
+
+ public static Bitmap createBitmap(String src) throws IOException {
+ if (src == null || src.length() == 0) {
+ // no image source defined
+ return null;
+ }
+
+ // InputStream inputStream = createInputStream(src);
+ InputStream inputStream = AssetAdapter.g.openFileAsStream(src);
+ if (inputStream == null)
+ throw new IllegalArgumentException("invalid bitmap source: " + src);
+
+ Bitmap bitmap = CanvasAdapter.g.decodeBitmap(inputStream);
+ inputStream.close();
+ return bitmap;
+ }
+
+ private BitmapUtils() {
+ throw new IllegalStateException();
+ }
+}
diff --git a/src/org/oscim/backend/CanvasAdapter.java b/vtm/src/org/oscim/backend/CanvasAdapter.java
similarity index 100%
rename from src/org/oscim/backend/CanvasAdapter.java
rename to vtm/src/org/oscim/backend/CanvasAdapter.java
diff --git a/src/org/oscim/backend/GL20.java b/vtm/src/org/oscim/backend/GL20.java
similarity index 100%
rename from src/org/oscim/backend/GL20.java
rename to vtm/src/org/oscim/backend/GL20.java
diff --git a/src/org/oscim/backend/GLAdapter.java b/vtm/src/org/oscim/backend/GLAdapter.java
similarity index 87%
rename from src/org/oscim/backend/GLAdapter.java
rename to vtm/src/org/oscim/backend/GLAdapter.java
index ac8367e5..77da351b 100644
--- a/src/org/oscim/backend/GLAdapter.java
+++ b/vtm/src/org/oscim/backend/GLAdapter.java
@@ -14,8 +14,8 @@
*/
package org.oscim.backend;
-import com.badlogic.gdx.backends.android.AndroidGL20;
+//import com.badlogic.gdx.backends.android.AndroidGL20;
public class GLAdapter {
- public static GL20 INSTANCE = new AndroidGL20();
+ public static GL20 INSTANCE; //= new AndroidGL20();
}
diff --git a/src/org/oscim/backend/Log.java b/vtm/src/org/oscim/backend/Log.java
similarity index 100%
rename from src/org/oscim/backend/Log.java
rename to vtm/src/org/oscim/backend/Log.java
diff --git a/src/org/oscim/backend/canvas/Bitmap.java b/vtm/src/org/oscim/backend/canvas/Bitmap.java
similarity index 100%
rename from src/org/oscim/backend/canvas/Bitmap.java
rename to vtm/src/org/oscim/backend/canvas/Bitmap.java
diff --git a/src/org/oscim/backend/canvas/Canvas.java b/vtm/src/org/oscim/backend/canvas/Canvas.java
similarity index 100%
rename from src/org/oscim/backend/canvas/Canvas.java
rename to vtm/src/org/oscim/backend/canvas/Canvas.java
diff --git a/src/org/oscim/backend/canvas/Color.java b/vtm/src/org/oscim/backend/canvas/Color.java
similarity index 100%
rename from src/org/oscim/backend/canvas/Color.java
rename to vtm/src/org/oscim/backend/canvas/Color.java
diff --git a/src/org/oscim/backend/canvas/Paint.java b/vtm/src/org/oscim/backend/canvas/Paint.java
similarity index 100%
rename from src/org/oscim/backend/canvas/Paint.java
rename to vtm/src/org/oscim/backend/canvas/Paint.java
diff --git a/src/org/oscim/backend/input/KeyEvent.java b/vtm/src/org/oscim/backend/input/KeyEvent.java
similarity index 100%
rename from src/org/oscim/backend/input/KeyEvent.java
rename to vtm/src/org/oscim/backend/input/KeyEvent.java
diff --git a/src/org/oscim/backend/input/MotionEvent.java b/vtm/src/org/oscim/backend/input/MotionEvent.java
similarity index 70%
rename from src/org/oscim/backend/input/MotionEvent.java
rename to vtm/src/org/oscim/backend/input/MotionEvent.java
index e41cd312..39e7564d 100644
--- a/src/org/oscim/backend/input/MotionEvent.java
+++ b/vtm/src/org/oscim/backend/input/MotionEvent.java
@@ -14,7 +14,7 @@
*/
package org.oscim.backend.input;
-public class MotionEvent {
+public abstract class MotionEvent {
public static final int ACTION_DOWN = 0;
public static final int ACTION_UP = 1;
@@ -28,34 +28,16 @@ public class MotionEvent {
public static final int ACTION_POINTER_INDEX_MASK = 0xff00;
public static final int ACTION_POINTER_INDEX_SHIFT = 8;
- public int getAction() {
- // TODO Auto-generated method stub
- return 0;
- }
+ public abstract int getAction();
- public float getX() {
- // TODO Auto-generated method stub
- return 0;
- }
+ public abstract float getX();
- public float getY() {
- // TODO Auto-generated method stub
- return 0;
- }
+ public abstract float getY();
- public float getX(int idx) {
- // TODO Auto-generated method stub
- return 0;
- }
+ public abstract float getX(int idx);
- public float getY(int idx) {
- // TODO Auto-generated method stub
- return 0;
- }
+ public abstract float getY(int idx);
- public int getPointerCount() {
- // TODO Auto-generated method stub
- return 0;
- }
+ public abstract int getPointerCount();
}
diff --git a/src/org/oscim/core/BoundingBox.java b/vtm/src/org/oscim/core/BoundingBox.java
similarity index 100%
rename from src/org/oscim/core/BoundingBox.java
rename to vtm/src/org/oscim/core/BoundingBox.java
diff --git a/src/org/oscim/core/GeoPoint.java b/vtm/src/org/oscim/core/GeoPoint.java
similarity index 100%
rename from src/org/oscim/core/GeoPoint.java
rename to vtm/src/org/oscim/core/GeoPoint.java
diff --git a/src/org/oscim/core/GeometryBuffer.java b/vtm/src/org/oscim/core/GeometryBuffer.java
similarity index 100%
rename from src/org/oscim/core/GeometryBuffer.java
rename to vtm/src/org/oscim/core/GeometryBuffer.java
diff --git a/src/org/oscim/core/MapElement.java b/vtm/src/org/oscim/core/MapElement.java
similarity index 100%
rename from src/org/oscim/core/MapElement.java
rename to vtm/src/org/oscim/core/MapElement.java
diff --git a/src/org/oscim/core/MapPosition.java b/vtm/src/org/oscim/core/MapPosition.java
similarity index 100%
rename from src/org/oscim/core/MapPosition.java
rename to vtm/src/org/oscim/core/MapPosition.java
diff --git a/src/org/oscim/core/MercatorProjection.java b/vtm/src/org/oscim/core/MercatorProjection.java
similarity index 100%
rename from src/org/oscim/core/MercatorProjection.java
rename to vtm/src/org/oscim/core/MercatorProjection.java
diff --git a/src/org/oscim/core/PointD.java b/vtm/src/org/oscim/core/PointD.java
similarity index 100%
rename from src/org/oscim/core/PointD.java
rename to vtm/src/org/oscim/core/PointD.java
diff --git a/src/org/oscim/core/PointF.java b/vtm/src/org/oscim/core/PointF.java
similarity index 100%
rename from src/org/oscim/core/PointF.java
rename to vtm/src/org/oscim/core/PointF.java
diff --git a/src/org/oscim/core/Tag.java b/vtm/src/org/oscim/core/Tag.java
similarity index 100%
rename from src/org/oscim/core/Tag.java
rename to vtm/src/org/oscim/core/Tag.java
diff --git a/src/org/oscim/core/TagSet.java b/vtm/src/org/oscim/core/TagSet.java
similarity index 100%
rename from src/org/oscim/core/TagSet.java
rename to vtm/src/org/oscim/core/TagSet.java
diff --git a/src/org/oscim/core/Tile.java b/vtm/src/org/oscim/core/Tile.java
similarity index 100%
rename from src/org/oscim/core/Tile.java
rename to vtm/src/org/oscim/core/Tile.java
diff --git a/src/org/oscim/layers/InputLayer.java b/vtm/src/org/oscim/layers/InputLayer.java
similarity index 100%
rename from src/org/oscim/layers/InputLayer.java
rename to vtm/src/org/oscim/layers/InputLayer.java
diff --git a/src/org/oscim/layers/Layer.java b/vtm/src/org/oscim/layers/Layer.java
similarity index 100%
rename from src/org/oscim/layers/Layer.java
rename to vtm/src/org/oscim/layers/Layer.java
diff --git a/src/org/oscim/layers/MapEventLayer.java b/vtm/src/org/oscim/layers/MapEventLayer.java
similarity index 100%
rename from src/org/oscim/layers/MapEventLayer.java
rename to vtm/src/org/oscim/layers/MapEventLayer.java
diff --git a/src/org/oscim/layers/labeling/Debug.java b/vtm/src/org/oscim/layers/labeling/Debug.java
similarity index 100%
rename from src/org/oscim/layers/labeling/Debug.java
rename to vtm/src/org/oscim/layers/labeling/Debug.java
diff --git a/src/org/oscim/layers/labeling/Label.java b/vtm/src/org/oscim/layers/labeling/Label.java
similarity index 100%
rename from src/org/oscim/layers/labeling/Label.java
rename to vtm/src/org/oscim/layers/labeling/Label.java
diff --git a/src/org/oscim/layers/labeling/LabelLayer.java b/vtm/src/org/oscim/layers/labeling/LabelLayer.java
similarity index 100%
rename from src/org/oscim/layers/labeling/LabelLayer.java
rename to vtm/src/org/oscim/layers/labeling/LabelLayer.java
diff --git a/src/org/oscim/layers/labeling/TextRenderLayer.java b/vtm/src/org/oscim/layers/labeling/TextRenderLayer.java
similarity index 100%
rename from src/org/oscim/layers/labeling/TextRenderLayer.java
rename to vtm/src/org/oscim/layers/labeling/TextRenderLayer.java
diff --git a/src/org/oscim/layers/overlay/BuildingOverlay.java b/vtm/src/org/oscim/layers/overlay/BuildingOverlay.java
similarity index 100%
rename from src/org/oscim/layers/overlay/BuildingOverlay.java
rename to vtm/src/org/oscim/layers/overlay/BuildingOverlay.java
diff --git a/src/org/oscim/layers/overlay/GenericOverlay.java b/vtm/src/org/oscim/layers/overlay/GenericOverlay.java
similarity index 100%
rename from src/org/oscim/layers/overlay/GenericOverlay.java
rename to vtm/src/org/oscim/layers/overlay/GenericOverlay.java
diff --git a/src/org/oscim/layers/overlay/ItemizedIconOverlay.java b/vtm/src/org/oscim/layers/overlay/ItemizedIconOverlay.java
similarity index 100%
rename from src/org/oscim/layers/overlay/ItemizedIconOverlay.java
rename to vtm/src/org/oscim/layers/overlay/ItemizedIconOverlay.java
diff --git a/src/org/oscim/layers/overlay/ItemizedOverlay.java b/vtm/src/org/oscim/layers/overlay/ItemizedOverlay.java
similarity index 94%
rename from src/org/oscim/layers/overlay/ItemizedOverlay.java
rename to vtm/src/org/oscim/layers/overlay/ItemizedOverlay.java
index a604233f..7d1be953 100644
--- a/src/org/oscim/layers/overlay/ItemizedOverlay.java
+++ b/vtm/src/org/oscim/layers/overlay/ItemizedOverlay.java
@@ -303,11 +303,11 @@ public abstract class ItemizedOverlay extends Overlay
* y coordinate of point to check
* @return true if the hit point is within the marker
*/
- protected boolean hitTest(final Item item, final android.graphics.drawable.Drawable marker,
- final int hitX,
- final int hitY) {
- return marker.getBounds().contains(hitX, hitY);
- }
+// protected boolean hitTest(final Item item, final android.graphics.drawable.Drawable marker,
+// final int hitX,
+// final int hitY) {
+// return marker.getBounds().contains(hitX, hitY);
+// }
/**
* Set whether or not to draw the focused item. The default is to draw it,
diff --git a/src/org/oscim/layers/overlay/MapScaleBar.java b/vtm/src/org/oscim/layers/overlay/MapScaleBar.java
similarity index 100%
rename from src/org/oscim/layers/overlay/MapScaleBar.java
rename to vtm/src/org/oscim/layers/overlay/MapScaleBar.java
diff --git a/src/org/oscim/layers/overlay/Overlay.java b/vtm/src/org/oscim/layers/overlay/Overlay.java
similarity index 100%
rename from src/org/oscim/layers/overlay/Overlay.java
rename to vtm/src/org/oscim/layers/overlay/Overlay.java
diff --git a/src/org/oscim/layers/overlay/OverlayItem.java b/vtm/src/org/oscim/layers/overlay/OverlayItem.java
similarity index 100%
rename from src/org/oscim/layers/overlay/OverlayItem.java
rename to vtm/src/org/oscim/layers/overlay/OverlayItem.java
diff --git a/src/org/oscim/layers/overlay/OverlayMarker.java b/vtm/src/org/oscim/layers/overlay/OverlayMarker.java
similarity index 100%
rename from src/org/oscim/layers/overlay/OverlayMarker.java
rename to vtm/src/org/oscim/layers/overlay/OverlayMarker.java
diff --git a/src/org/oscim/layers/overlay/PathOverlay.java b/vtm/src/org/oscim/layers/overlay/PathOverlay.java
similarity index 100%
rename from src/org/oscim/layers/overlay/PathOverlay.java
rename to vtm/src/org/oscim/layers/overlay/PathOverlay.java
diff --git a/src/org/oscim/layers/tile/JobQueue.java b/vtm/src/org/oscim/layers/tile/JobQueue.java
similarity index 100%
rename from src/org/oscim/layers/tile/JobQueue.java
rename to vtm/src/org/oscim/layers/tile/JobQueue.java
diff --git a/src/org/oscim/layers/tile/MapTile.java b/vtm/src/org/oscim/layers/tile/MapTile.java
similarity index 100%
rename from src/org/oscim/layers/tile/MapTile.java
rename to vtm/src/org/oscim/layers/tile/MapTile.java
diff --git a/src/org/oscim/layers/tile/TileDistanceSort.java b/vtm/src/org/oscim/layers/tile/TileDistanceSort.java
similarity index 100%
rename from src/org/oscim/layers/tile/TileDistanceSort.java
rename to vtm/src/org/oscim/layers/tile/TileDistanceSort.java
diff --git a/src/org/oscim/layers/tile/TileLayer.java b/vtm/src/org/oscim/layers/tile/TileLayer.java
similarity index 100%
rename from src/org/oscim/layers/tile/TileLayer.java
rename to vtm/src/org/oscim/layers/tile/TileLayer.java
diff --git a/src/org/oscim/layers/tile/TileLoader.java b/vtm/src/org/oscim/layers/tile/TileLoader.java
similarity index 100%
rename from src/org/oscim/layers/tile/TileLoader.java
rename to vtm/src/org/oscim/layers/tile/TileLoader.java
diff --git a/src/org/oscim/layers/tile/TileManager.java b/vtm/src/org/oscim/layers/tile/TileManager.java
similarity index 100%
rename from src/org/oscim/layers/tile/TileManager.java
rename to vtm/src/org/oscim/layers/tile/TileManager.java
diff --git a/src/org/oscim/layers/tile/TileRenderLayer.java b/vtm/src/org/oscim/layers/tile/TileRenderLayer.java
similarity index 100%
rename from src/org/oscim/layers/tile/TileRenderLayer.java
rename to vtm/src/org/oscim/layers/tile/TileRenderLayer.java
diff --git a/src/org/oscim/layers/tile/TileRenderer.java b/vtm/src/org/oscim/layers/tile/TileRenderer.java
similarity index 99%
rename from src/org/oscim/layers/tile/TileRenderer.java
rename to vtm/src/org/oscim/layers/tile/TileRenderer.java
index 7bbf0f5d..c5b5bd54 100644
--- a/src/org/oscim/layers/tile/TileRenderer.java
+++ b/vtm/src/org/oscim/layers/tile/TileRenderer.java
@@ -66,6 +66,7 @@ public class TileRenderer {
mProjMatrix.setValue(14, 0);
mProjMatrix.multiplyRhs(m.view);
+ GL.glDepthMask(true);
GL.glClear(GL20.GL_DEPTH_BUFFER_BIT);
GL.glDepthFunc(GL20.GL_LESS);
diff --git a/src/org/oscim/layers/tile/TileSet.java b/vtm/src/org/oscim/layers/tile/TileSet.java
similarity index 100%
rename from src/org/oscim/layers/tile/TileSet.java
rename to vtm/src/org/oscim/layers/tile/TileSet.java
diff --git a/src/org/oscim/layers/tile/bitmap/AbstractTileSource.java b/vtm/src/org/oscim/layers/tile/bitmap/AbstractTileSource.java
similarity index 100%
rename from src/org/oscim/layers/tile/bitmap/AbstractTileSource.java
rename to vtm/src/org/oscim/layers/tile/bitmap/AbstractTileSource.java
diff --git a/src/org/oscim/layers/tile/bitmap/ArcGISWorldShaded.java b/vtm/src/org/oscim/layers/tile/bitmap/ArcGISWorldShaded.java
similarity index 100%
rename from src/org/oscim/layers/tile/bitmap/ArcGISWorldShaded.java
rename to vtm/src/org/oscim/layers/tile/bitmap/ArcGISWorldShaded.java
diff --git a/src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java b/vtm/src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
similarity index 100%
rename from src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
rename to vtm/src/org/oscim/layers/tile/bitmap/BitmapTileLayer.java
diff --git a/src/org/oscim/layers/tile/bitmap/MapQuestAerial.java b/vtm/src/org/oscim/layers/tile/bitmap/MapQuestAerial.java
similarity index 100%
rename from src/org/oscim/layers/tile/bitmap/MapQuestAerial.java
rename to vtm/src/org/oscim/layers/tile/bitmap/MapQuestAerial.java
diff --git a/src/org/oscim/layers/tile/bitmap/NaturalEarth.java b/vtm/src/org/oscim/layers/tile/bitmap/NaturalEarth.java
similarity index 100%
rename from src/org/oscim/layers/tile/bitmap/NaturalEarth.java
rename to vtm/src/org/oscim/layers/tile/bitmap/NaturalEarth.java
diff --git a/src/org/oscim/layers/tile/bitmap/OpenStreetMapMapnik.java b/vtm/src/org/oscim/layers/tile/bitmap/OpenStreetMapMapnik.java
similarity index 100%
rename from src/org/oscim/layers/tile/bitmap/OpenStreetMapMapnik.java
rename to vtm/src/org/oscim/layers/tile/bitmap/OpenStreetMapMapnik.java
diff --git a/src/org/oscim/layers/tile/bitmap/TileSource.java b/vtm/src/org/oscim/layers/tile/bitmap/TileSource.java
similarity index 100%
rename from src/org/oscim/layers/tile/bitmap/TileSource.java
rename to vtm/src/org/oscim/layers/tile/bitmap/TileSource.java
diff --git a/src/org/oscim/layers/tile/geojson/GeoJsonTileLayer.java b/vtm/src/org/oscim/layers/tile/geojson/GeoJsonTileLayer.java
similarity index 100%
rename from src/org/oscim/layers/tile/geojson/GeoJsonTileLayer.java
rename to vtm/src/org/oscim/layers/tile/geojson/GeoJsonTileLayer.java
diff --git a/src/org/oscim/layers/tile/test/TestTileLayer.java b/vtm/src/org/oscim/layers/tile/test/TestTileLayer.java
similarity index 100%
rename from src/org/oscim/layers/tile/test/TestTileLayer.java
rename to vtm/src/org/oscim/layers/tile/test/TestTileLayer.java
diff --git a/src/org/oscim/layers/tile/vector/MapTileLayer.java b/vtm/src/org/oscim/layers/tile/vector/MapTileLayer.java
similarity index 100%
rename from src/org/oscim/layers/tile/vector/MapTileLayer.java
rename to vtm/src/org/oscim/layers/tile/vector/MapTileLayer.java
diff --git a/src/org/oscim/layers/tile/vector/MapTileLoader.java b/vtm/src/org/oscim/layers/tile/vector/MapTileLoader.java
similarity index 100%
rename from src/org/oscim/layers/tile/vector/MapTileLoader.java
rename to vtm/src/org/oscim/layers/tile/vector/MapTileLoader.java
diff --git a/src/org/oscim/layers/tile/vector/WayDecorator.java b/vtm/src/org/oscim/layers/tile/vector/WayDecorator.java
similarity index 100%
rename from src/org/oscim/layers/tile/vector/WayDecorator.java
rename to vtm/src/org/oscim/layers/tile/vector/WayDecorator.java
diff --git a/src/org/oscim/renderer/BufferObject.java b/vtm/src/org/oscim/renderer/BufferObject.java
similarity index 96%
rename from src/org/oscim/renderer/BufferObject.java
rename to vtm/src/org/oscim/renderer/BufferObject.java
index 98a3848f..cb40b192 100644
--- a/src/org/oscim/renderer/BufferObject.java
+++ b/vtm/src/org/oscim/renderer/BufferObject.java
@@ -52,6 +52,10 @@ public final class BufferObject {
bufferType = type;
}
+ if (buf.position() != 0){
+ Log.d(TAG, "rewind your buffer: " + buf.position());
+ }
+
GL.glBindBuffer(type, id);
// reuse memory allocated for vbo when possible and allocated
@@ -60,11 +64,11 @@ public final class BufferObject {
GL.glBufferSubData(type, 0, newSize, buf);
} else {
mBufferMemoryUsage += newSize - size;
-
size = newSize;
-
GL.glBufferData(type, size, buf, GL20.GL_DYNAMIC_DRAW);
+ //GL.glBufferData(type, size, buf, GL20.GL_STATIC_DRAW);
}
+ //GL.glFinish();
}
public void bindArrayBuffer() {
diff --git a/src/org/oscim/renderer/GLRenderer.java b/vtm/src/org/oscim/renderer/GLRenderer.java
similarity index 93%
rename from src/org/oscim/renderer/GLRenderer.java
rename to vtm/src/org/oscim/renderer/GLRenderer.java
index 4380e5fa..8da792ec 100644
--- a/src/org/oscim/renderer/GLRenderer.java
+++ b/vtm/src/org/oscim/renderer/GLRenderer.java
@@ -135,13 +135,14 @@ public class GLRenderer {
mClearColor = GlUtils.colorToFloat(t.getMapBackground());
mUpdateColor = true;
}
+ public static boolean alwaysAllocBuffer = false;
/**
* Only use on GL Thread!
* Get a native ShortBuffer for temporary use.
*/
public static ShortBuffer getShortBuffer(int size) {
- if (tmpBufferSize < size * 2)
+ if (alwaysAllocBuffer || tmpBufferSize < size * 2)
growBuffer(size * 2);
else
shortBuffer.clear();
@@ -154,7 +155,7 @@ public class GLRenderer {
* Get a native FloatBuffer for temporary use.
*/
public static FloatBuffer getFloatBuffer(int size) {
- if (tmpBufferSize < size * 4)
+ if (alwaysAllocBuffer || tmpBufferSize < size * 4)
growBuffer(size * 4);
else
floatBuffer.clear();
@@ -167,7 +168,7 @@ public class GLRenderer {
* Get a native IntBuffer for temporary use.
*/
public static IntBuffer getIntBuffer(int size) {
- if (tmpBufferSize < size * 4)
+ if (alwaysAllocBuffer || tmpBufferSize < size * 4)
growBuffer(size * 4);
else
intBuffer.clear();
@@ -279,19 +280,23 @@ public class GLRenderer {
}
/* update layers */
- RenderLayer[] overlays = mMapView.getLayerManager().getRenderLayers();
+ RenderLayer[] layers = mMapView.getLayerManager().getRenderLayers();
- for (int i = 0, n = overlays.length; i < n; i++)
- overlays[i].update(pos, changed, mMatrices);
+ for (int i = 0, n = layers.length; i < n; i++)
+ layers[i].update(pos, changed, mMatrices);
- /* draw layers */
- for (int i = 0, n = overlays.length; i < n; i++) {
- RenderLayer renderLayer = overlays[i];
+ /* compile layers */
+ for (int i = 0, n = layers.length; i < n; i++) {
+ RenderLayer renderLayer = layers[i];
if (renderLayer.newData) {
renderLayer.compile();
renderLayer.newData = false;
}
+ }
+
+ for (int i = 0, n = layers.length; i < n; i++) {
+ RenderLayer renderLayer = layers[i];
if (renderLayer.isReady)
renderLayer.render(mMapPosition, mMatrices);
@@ -366,7 +371,7 @@ public class GLRenderer {
indices[i + 4] = (short) (j + 1);
indices[i + 5] = (short) (j + 3);
}
-
+ GLRenderer.getShortBuffer(indices.length);
shortBuffer.put(indices);
shortBuffer.flip();
diff --git a/src/org/oscim/renderer/GLState.java b/vtm/src/org/oscim/renderer/GLState.java
similarity index 100%
rename from src/org/oscim/renderer/GLState.java
rename to vtm/src/org/oscim/renderer/GLState.java
diff --git a/src/org/oscim/renderer/RenderLayer.java b/vtm/src/org/oscim/renderer/RenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/RenderLayer.java
rename to vtm/src/org/oscim/renderer/RenderLayer.java
diff --git a/src/org/oscim/renderer/atlas/SpriteManager.java b/vtm/src/org/oscim/renderer/atlas/SpriteManager.java
similarity index 100%
rename from src/org/oscim/renderer/atlas/SpriteManager.java
rename to vtm/src/org/oscim/renderer/atlas/SpriteManager.java
diff --git a/src/org/oscim/renderer/atlas/TextureAtlas.java b/vtm/src/org/oscim/renderer/atlas/TextureAtlas.java
similarity index 100%
rename from src/org/oscim/renderer/atlas/TextureAtlas.java
rename to vtm/src/org/oscim/renderer/atlas/TextureAtlas.java
diff --git a/src/org/oscim/renderer/atlas/TextureRegion.java b/vtm/src/org/oscim/renderer/atlas/TextureRegion.java
similarity index 100%
rename from src/org/oscim/renderer/atlas/TextureRegion.java
rename to vtm/src/org/oscim/renderer/atlas/TextureRegion.java
diff --git a/src/org/oscim/renderer/layers/BasicRenderLayer.java b/vtm/src/org/oscim/renderer/layers/BasicRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/BasicRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/BasicRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/BitmapRenderLayer.java b/vtm/src/org/oscim/renderer/layers/BitmapRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/BitmapRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/BitmapRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/CustomRenderLayer.java b/vtm/src/org/oscim/renderer/layers/CustomRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/CustomRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/CustomRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/CustomRenderLayer2.java b/vtm/src/org/oscim/renderer/layers/CustomRenderLayer2.java
similarity index 100%
rename from src/org/oscim/renderer/layers/CustomRenderLayer2.java
rename to vtm/src/org/oscim/renderer/layers/CustomRenderLayer2.java
diff --git a/src/org/oscim/renderer/layers/ExtrusionRenderLayer.java b/vtm/src/org/oscim/renderer/layers/ExtrusionRenderLayer.java
similarity index 97%
rename from src/org/oscim/renderer/layers/ExtrusionRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/ExtrusionRenderLayer.java
index 48e15f81..ff743e7a 100644
--- a/src/org/oscim/renderer/layers/ExtrusionRenderLayer.java
+++ b/vtm/src/org/oscim/renderer/layers/ExtrusionRenderLayer.java
@@ -14,6 +14,10 @@
*/
package org.oscim.renderer.layers;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+
import org.oscim.backend.GL20;
import org.oscim.backend.GLAdapter;
import org.oscim.backend.Log;
@@ -60,6 +64,16 @@ public class ExtrusionRenderLayer extends RenderLayer {
private final static int SHADER = 0;
+ private static ShortBuffer getShortBuffer(int size) {
+ ByteBuffer buf = ByteBuffer
+ .allocateDirect(size)
+ .order(ByteOrder.nativeOrder());
+
+ return buf.asShortBuffer();
+
+ }
+
+
private boolean initShader() {
initialized = true;
@@ -120,8 +134,8 @@ public class ExtrusionRenderLayer extends RenderLayer {
continue;
if (!el.compiled) {
- int verticesBytes = el.mNumVertices * 8;
- el.compile(GLRenderer.getShortBuffer(verticesBytes));
+ int bytes = el.mNumVertices * 8 * 2;
+ el.compile(getShortBuffer(bytes));
GlUtils.checkGlError("...");
}
diff --git a/src/org/oscim/renderer/layers/GridRenderLayer.java b/vtm/src/org/oscim/renderer/layers/GridRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/GridRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/GridRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/LabelRenderLayer.java b/vtm/src/org/oscim/renderer/layers/LabelRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/LabelRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/LabelRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/TextRenderLayer.java b/vtm/src/org/oscim/renderer/layers/TextRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/TextRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/TextRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/test/AtlasRenderLayer.java b/vtm/src/org/oscim/renderer/layers/test/AtlasRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/test/AtlasRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/test/AtlasRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/test/ModelRenderLayer.java b/vtm/src/org/oscim/renderer/layers/test/ModelRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/test/ModelRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/test/ModelRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/test/SymbolRenderLayer.java b/vtm/src/org/oscim/renderer/layers/test/SymbolRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/test/SymbolRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/test/SymbolRenderLayer.java
diff --git a/src/org/oscim/renderer/layers/test/TestRenderLayer.java b/vtm/src/org/oscim/renderer/layers/test/TestRenderLayer.java
similarity index 100%
rename from src/org/oscim/renderer/layers/test/TestRenderLayer.java
rename to vtm/src/org/oscim/renderer/layers/test/TestRenderLayer.java
diff --git a/src/org/oscim/renderer/sublayers/BitmapLayer.java b/vtm/src/org/oscim/renderer/sublayers/BitmapLayer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/BitmapLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/BitmapLayer.java
diff --git a/src/org/oscim/renderer/sublayers/BitmapRenderer.java b/vtm/src/org/oscim/renderer/sublayers/BitmapRenderer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/BitmapRenderer.java
rename to vtm/src/org/oscim/renderer/sublayers/BitmapRenderer.java
diff --git a/src/org/oscim/renderer/sublayers/ExtrusionLayer.java b/vtm/src/org/oscim/renderer/sublayers/ExtrusionLayer.java
similarity index 99%
rename from src/org/oscim/renderer/sublayers/ExtrusionLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/ExtrusionLayer.java
index 0059ea5e..7c81d672 100644
--- a/src/org/oscim/renderer/sublayers/ExtrusionLayer.java
+++ b/vtm/src/org/oscim/renderer/sublayers/ExtrusionLayer.java
@@ -136,6 +136,7 @@ public class ExtrusionLayer extends Layer {
// vector-tile-map does not produce implicty closed
// polygons (yet)
len -= 2;
+ Log.d(TAG, "explicit closed poly " + len);
}
// need at least three points
@@ -403,6 +404,8 @@ public class ExtrusionLayer extends Layer {
int size = mNumIndices * 2;
vboIndices = BufferObject.get(size);
vboIndices.loadBufferData(sbuf, size, GL20.GL_ELEMENT_ARRAY_BUFFER);
+
+ GL.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
// upload vertices
sbuf.clear();
@@ -414,7 +417,6 @@ public class ExtrusionLayer extends Layer {
vboVertices = BufferObject.get(size);
vboVertices.loadBufferData(sbuf, size, GL20.GL_ARRAY_BUFFER);
- GL.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
GL.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
for (int i = 0; i < 4; i++)
@@ -503,7 +505,4 @@ public class ExtrusionLayer extends Layer {
ShortBuffer io,
int ioffset);
- static {
- System.loadLibrary("triangle");
- }
}
diff --git a/src/org/oscim/renderer/sublayers/Layer.java b/vtm/src/org/oscim/renderer/sublayers/Layer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/Layer.java
rename to vtm/src/org/oscim/renderer/sublayers/Layer.java
diff --git a/src/org/oscim/renderer/sublayers/Layers.java b/vtm/src/org/oscim/renderer/sublayers/Layers.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/Layers.java
rename to vtm/src/org/oscim/renderer/sublayers/Layers.java
diff --git a/src/org/oscim/renderer/sublayers/LineLayer.java b/vtm/src/org/oscim/renderer/sublayers/LineLayer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/LineLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/LineLayer.java
diff --git a/src/org/oscim/renderer/sublayers/LineRenderer.java b/vtm/src/org/oscim/renderer/sublayers/LineRenderer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/LineRenderer.java
rename to vtm/src/org/oscim/renderer/sublayers/LineRenderer.java
diff --git a/src/org/oscim/renderer/sublayers/LineTexLayer.java b/vtm/src/org/oscim/renderer/sublayers/LineTexLayer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/LineTexLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/LineTexLayer.java
diff --git a/src/org/oscim/renderer/sublayers/LineTexRenderer.java b/vtm/src/org/oscim/renderer/sublayers/LineTexRenderer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/LineTexRenderer.java
rename to vtm/src/org/oscim/renderer/sublayers/LineTexRenderer.java
diff --git a/src/org/oscim/renderer/sublayers/MeshLayer.java b/vtm/src/org/oscim/renderer/sublayers/MeshLayer.java
similarity index 98%
rename from src/org/oscim/renderer/sublayers/MeshLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/MeshLayer.java
index b8626e01..6514ef78 100644
--- a/src/org/oscim/renderer/sublayers/MeshLayer.java
+++ b/vtm/src/org/oscim/renderer/sublayers/MeshLayer.java
@@ -103,8 +103,4 @@ public class MeshLayer extends Layer {
public static native int tessGetIndices(long ctx, short[] indices);
-
- static {
- System.loadLibrary("tessellate");
- }
}
diff --git a/src/org/oscim/renderer/sublayers/MeshRenderer.java b/vtm/src/org/oscim/renderer/sublayers/MeshRenderer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/MeshRenderer.java
rename to vtm/src/org/oscim/renderer/sublayers/MeshRenderer.java
diff --git a/src/org/oscim/renderer/sublayers/PolygonLayer.java b/vtm/src/org/oscim/renderer/sublayers/PolygonLayer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/PolygonLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/PolygonLayer.java
diff --git a/src/org/oscim/renderer/sublayers/PolygonRenderer.java b/vtm/src/org/oscim/renderer/sublayers/PolygonRenderer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/PolygonRenderer.java
rename to vtm/src/org/oscim/renderer/sublayers/PolygonRenderer.java
diff --git a/src/org/oscim/renderer/sublayers/SymbolItem.java b/vtm/src/org/oscim/renderer/sublayers/SymbolItem.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/SymbolItem.java
rename to vtm/src/org/oscim/renderer/sublayers/SymbolItem.java
diff --git a/src/org/oscim/renderer/sublayers/SymbolLayer.java b/vtm/src/org/oscim/renderer/sublayers/SymbolLayer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/SymbolLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/SymbolLayer.java
diff --git a/src/org/oscim/renderer/sublayers/TextItem.java b/vtm/src/org/oscim/renderer/sublayers/TextItem.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/TextItem.java
rename to vtm/src/org/oscim/renderer/sublayers/TextItem.java
diff --git a/src/org/oscim/renderer/sublayers/TextLayer.java b/vtm/src/org/oscim/renderer/sublayers/TextLayer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/TextLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/TextLayer.java
diff --git a/src/org/oscim/renderer/sublayers/TextureItem.java b/vtm/src/org/oscim/renderer/sublayers/TextureItem.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/TextureItem.java
rename to vtm/src/org/oscim/renderer/sublayers/TextureItem.java
diff --git a/src/org/oscim/renderer/sublayers/TextureLayer.java b/vtm/src/org/oscim/renderer/sublayers/TextureLayer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/TextureLayer.java
rename to vtm/src/org/oscim/renderer/sublayers/TextureLayer.java
diff --git a/src/org/oscim/renderer/sublayers/TextureRenderer.java b/vtm/src/org/oscim/renderer/sublayers/TextureRenderer.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/TextureRenderer.java
rename to vtm/src/org/oscim/renderer/sublayers/TextureRenderer.java
diff --git a/src/org/oscim/renderer/sublayers/VertexItem.java b/vtm/src/org/oscim/renderer/sublayers/VertexItem.java
similarity index 100%
rename from src/org/oscim/renderer/sublayers/VertexItem.java
rename to vtm/src/org/oscim/renderer/sublayers/VertexItem.java
diff --git a/src/org/oscim/theme/ExternalRenderTheme.java b/vtm/src/org/oscim/theme/ExternalRenderTheme.java
similarity index 100%
rename from src/org/oscim/theme/ExternalRenderTheme.java
rename to vtm/src/org/oscim/theme/ExternalRenderTheme.java
diff --git a/src/org/oscim/theme/IRenderCallback.java b/vtm/src/org/oscim/theme/IRenderCallback.java
similarity index 100%
rename from src/org/oscim/theme/IRenderCallback.java
rename to vtm/src/org/oscim/theme/IRenderCallback.java
diff --git a/src/org/oscim/theme/IRenderTheme.java b/vtm/src/org/oscim/theme/IRenderTheme.java
similarity index 100%
rename from src/org/oscim/theme/IRenderTheme.java
rename to vtm/src/org/oscim/theme/IRenderTheme.java
diff --git a/src/org/oscim/theme/InternalRenderTheme.java b/vtm/src/org/oscim/theme/InternalRenderTheme.java
similarity index 78%
rename from src/org/oscim/theme/InternalRenderTheme.java
rename to vtm/src/org/oscim/theme/InternalRenderTheme.java
index 434c3066..abd664bd 100644
--- a/src/org/oscim/theme/InternalRenderTheme.java
+++ b/vtm/src/org/oscim/theme/InternalRenderTheme.java
@@ -1,6 +1,6 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
- * Copyright 2013 Hannes Janetzek.org
+ * Copyright 2013 Hannes Janetzek
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@@ -17,14 +17,16 @@ package org.oscim.theme;
import java.io.InputStream;
+import org.oscim.backend.AssetAdapter;
+
/**
* Enumeration of all internal rendering themes.
*/
public enum InternalRenderTheme implements Theme {
- DEFAULT("/org/oscim/theme/styles/default.xml"),
- TRONRENDER("/org/oscim/theme/styles/tronrender.xml"),
- MAPNIK("/org/oscim/theme/styles/carto.xml");
+ DEFAULT("styles/default.xml"),
+ TRONRENDER("styles/tronrender.xml"),
+ MAPNIK("styles/carto.xml");
private final String mPath;
@@ -34,6 +36,7 @@ public enum InternalRenderTheme implements Theme {
@Override
public InputStream getRenderThemeAsStream() {
- return InternalRenderTheme.class.getResourceAsStream(mPath);
+ return AssetAdapter.g.openFileAsStream(mPath);
+ //InternalRenderTheme.class.getResourceAsStream(mPath);
}
}
diff --git a/src/org/oscim/theme/MatchingCacheKey.java b/vtm/src/org/oscim/theme/MatchingCacheKey.java
similarity index 100%
rename from src/org/oscim/theme/MatchingCacheKey.java
rename to vtm/src/org/oscim/theme/MatchingCacheKey.java
diff --git a/src/org/oscim/theme/RenderTheme.java b/vtm/src/org/oscim/theme/RenderTheme.java
similarity index 100%
rename from src/org/oscim/theme/RenderTheme.java
rename to vtm/src/org/oscim/theme/RenderTheme.java
diff --git a/src/org/oscim/theme/RenderThemeHandler.java b/vtm/src/org/oscim/theme/RenderThemeHandler.java
similarity index 98%
rename from src/org/oscim/theme/RenderThemeHandler.java
rename to vtm/src/org/oscim/theme/RenderThemeHandler.java
index 2843756f..4f7062fa 100644
--- a/src/org/oscim/theme/RenderThemeHandler.java
+++ b/vtm/src/org/oscim/theme/RenderThemeHandler.java
@@ -83,9 +83,13 @@ public class RenderThemeHandler extends DefaultHandler {
public static IRenderTheme getRenderTheme(InputStream inputStream)
throws SAXException,
ParserConfigurationException, IOException {
+
RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
- XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser()
- .getXMLReader();
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+
+ XMLReader xmlReader = factory.newSAXParser().getXMLReader();
xmlReader.setContentHandler(renderThemeHandler);
xmlReader.parse(new InputSource(inputStream));
return renderThemeHandler.mRenderTheme;
@@ -357,7 +361,7 @@ public class RenderThemeHandler extends DefaultHandler {
"missing attribute 'img' for element: "
+ elementName);
- Bitmap bitmap = BitmapUtils.createBitmap("jar:" + img);
+ Bitmap bitmap = BitmapUtils.createBitmap("styles/" + img);
mTextureAtlas = new TextureAtlas(bitmap);
}
diff --git a/src/org/oscim/theme/Theme.java b/vtm/src/org/oscim/theme/Theme.java
similarity index 100%
rename from src/org/oscim/theme/Theme.java
rename to vtm/src/org/oscim/theme/Theme.java
diff --git a/src/org/oscim/theme/renderTheme.xsd b/vtm/src/org/oscim/theme/renderTheme.xsd
similarity index 100%
rename from src/org/oscim/theme/renderTheme.xsd
rename to vtm/src/org/oscim/theme/renderTheme.xsd
diff --git a/src/org/oscim/theme/renderinstruction/Area.java b/vtm/src/org/oscim/theme/renderinstruction/Area.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/Area.java
rename to vtm/src/org/oscim/theme/renderinstruction/Area.java
diff --git a/src/org/oscim/theme/renderinstruction/AreaLevel.java b/vtm/src/org/oscim/theme/renderinstruction/AreaLevel.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/AreaLevel.java
rename to vtm/src/org/oscim/theme/renderinstruction/AreaLevel.java
diff --git a/src/org/oscim/theme/renderinstruction/Circle.java b/vtm/src/org/oscim/theme/renderinstruction/Circle.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/Circle.java
rename to vtm/src/org/oscim/theme/renderinstruction/Circle.java
diff --git a/src/org/oscim/theme/renderinstruction/Line.java b/vtm/src/org/oscim/theme/renderinstruction/Line.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/Line.java
rename to vtm/src/org/oscim/theme/renderinstruction/Line.java
diff --git a/src/org/oscim/theme/renderinstruction/LineSymbol.java b/vtm/src/org/oscim/theme/renderinstruction/LineSymbol.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/LineSymbol.java
rename to vtm/src/org/oscim/theme/renderinstruction/LineSymbol.java
diff --git a/src/org/oscim/theme/renderinstruction/RenderInstruction.java b/vtm/src/org/oscim/theme/renderinstruction/RenderInstruction.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/RenderInstruction.java
rename to vtm/src/org/oscim/theme/renderinstruction/RenderInstruction.java
diff --git a/src/org/oscim/theme/renderinstruction/Symbol.java b/vtm/src/org/oscim/theme/renderinstruction/Symbol.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/Symbol.java
rename to vtm/src/org/oscim/theme/renderinstruction/Symbol.java
diff --git a/src/org/oscim/theme/renderinstruction/Text.java b/vtm/src/org/oscim/theme/renderinstruction/Text.java
similarity index 100%
rename from src/org/oscim/theme/renderinstruction/Text.java
rename to vtm/src/org/oscim/theme/renderinstruction/Text.java
diff --git a/src/org/oscim/theme/rule/AnyMatcher.java b/vtm/src/org/oscim/theme/rule/AnyMatcher.java
similarity index 100%
rename from src/org/oscim/theme/rule/AnyMatcher.java
rename to vtm/src/org/oscim/theme/rule/AnyMatcher.java
diff --git a/src/org/oscim/theme/rule/AttributeMatcher.java b/vtm/src/org/oscim/theme/rule/AttributeMatcher.java
similarity index 100%
rename from src/org/oscim/theme/rule/AttributeMatcher.java
rename to vtm/src/org/oscim/theme/rule/AttributeMatcher.java
diff --git a/src/org/oscim/theme/rule/Closed.java b/vtm/src/org/oscim/theme/rule/Closed.java
similarity index 100%
rename from src/org/oscim/theme/rule/Closed.java
rename to vtm/src/org/oscim/theme/rule/Closed.java
diff --git a/src/org/oscim/theme/rule/Element.java b/vtm/src/org/oscim/theme/rule/Element.java
similarity index 100%
rename from src/org/oscim/theme/rule/Element.java
rename to vtm/src/org/oscim/theme/rule/Element.java
diff --git a/src/org/oscim/theme/rule/MultiKeyMatcher.java b/vtm/src/org/oscim/theme/rule/MultiKeyMatcher.java
similarity index 100%
rename from src/org/oscim/theme/rule/MultiKeyMatcher.java
rename to vtm/src/org/oscim/theme/rule/MultiKeyMatcher.java
diff --git a/src/org/oscim/theme/rule/MultiValueMatcher.java b/vtm/src/org/oscim/theme/rule/MultiValueMatcher.java
similarity index 100%
rename from src/org/oscim/theme/rule/MultiValueMatcher.java
rename to vtm/src/org/oscim/theme/rule/MultiValueMatcher.java
diff --git a/src/org/oscim/theme/rule/NegativeMatcher.java b/vtm/src/org/oscim/theme/rule/NegativeMatcher.java
similarity index 100%
rename from src/org/oscim/theme/rule/NegativeMatcher.java
rename to vtm/src/org/oscim/theme/rule/NegativeMatcher.java
diff --git a/src/org/oscim/theme/rule/NegativeRule.java b/vtm/src/org/oscim/theme/rule/NegativeRule.java
similarity index 100%
rename from src/org/oscim/theme/rule/NegativeRule.java
rename to vtm/src/org/oscim/theme/rule/NegativeRule.java
diff --git a/src/org/oscim/theme/rule/PositiveRule.java b/vtm/src/org/oscim/theme/rule/PositiveRule.java
similarity index 100%
rename from src/org/oscim/theme/rule/PositiveRule.java
rename to vtm/src/org/oscim/theme/rule/PositiveRule.java
diff --git a/src/org/oscim/theme/rule/Rule.java b/vtm/src/org/oscim/theme/rule/Rule.java
similarity index 100%
rename from src/org/oscim/theme/rule/Rule.java
rename to vtm/src/org/oscim/theme/rule/Rule.java
diff --git a/src/org/oscim/theme/rule/RuleOptimizer.java b/vtm/src/org/oscim/theme/rule/RuleOptimizer.java
similarity index 100%
rename from src/org/oscim/theme/rule/RuleOptimizer.java
rename to vtm/src/org/oscim/theme/rule/RuleOptimizer.java
diff --git a/src/org/oscim/theme/rule/SingleKeyMatcher.java b/vtm/src/org/oscim/theme/rule/SingleKeyMatcher.java
similarity index 100%
rename from src/org/oscim/theme/rule/SingleKeyMatcher.java
rename to vtm/src/org/oscim/theme/rule/SingleKeyMatcher.java
diff --git a/src/org/oscim/theme/rule/SingleValueMatcher.java b/vtm/src/org/oscim/theme/rule/SingleValueMatcher.java
similarity index 100%
rename from src/org/oscim/theme/rule/SingleValueMatcher.java
rename to vtm/src/org/oscim/theme/rule/SingleValueMatcher.java
diff --git a/src/org/oscim/tilesource/ITileDataSink.java b/vtm/src/org/oscim/tilesource/ITileDataSink.java
similarity index 100%
rename from src/org/oscim/tilesource/ITileDataSink.java
rename to vtm/src/org/oscim/tilesource/ITileDataSink.java
diff --git a/src/org/oscim/tilesource/ITileDataSource.java b/vtm/src/org/oscim/tilesource/ITileDataSource.java
similarity index 100%
rename from src/org/oscim/tilesource/ITileDataSource.java
rename to vtm/src/org/oscim/tilesource/ITileDataSource.java
diff --git a/src/org/oscim/tilesource/MapInfo.java b/vtm/src/org/oscim/tilesource/MapInfo.java
similarity index 100%
rename from src/org/oscim/tilesource/MapInfo.java
rename to vtm/src/org/oscim/tilesource/MapInfo.java
diff --git a/src/org/oscim/tilesource/TileSource.java b/vtm/src/org/oscim/tilesource/TileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/TileSource.java
rename to vtm/src/org/oscim/tilesource/TileSource.java
diff --git a/src/org/oscim/tilesource/TileSources.java b/vtm/src/org/oscim/tilesource/TileSources.java
similarity index 100%
rename from src/org/oscim/tilesource/TileSources.java
rename to vtm/src/org/oscim/tilesource/TileSources.java
diff --git a/src/org/oscim/tilesource/common/LwHttp.java b/vtm/src/org/oscim/tilesource/common/LwHttp.java
similarity index 100%
rename from src/org/oscim/tilesource/common/LwHttp.java
rename to vtm/src/org/oscim/tilesource/common/LwHttp.java
diff --git a/src/org/oscim/tilesource/common/PbfDecoder.java b/vtm/src/org/oscim/tilesource/common/PbfDecoder.java
similarity index 100%
rename from src/org/oscim/tilesource/common/PbfDecoder.java
rename to vtm/src/org/oscim/tilesource/common/PbfDecoder.java
diff --git a/src/org/oscim/tilesource/common/PbfTileDataSource.java b/vtm/src/org/oscim/tilesource/common/PbfTileDataSource.java
similarity index 100%
rename from src/org/oscim/tilesource/common/PbfTileDataSource.java
rename to vtm/src/org/oscim/tilesource/common/PbfTileDataSource.java
diff --git a/src/org/oscim/tilesource/common/UrlTileSource.java b/vtm/src/org/oscim/tilesource/common/UrlTileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/common/UrlTileSource.java
rename to vtm/src/org/oscim/tilesource/common/UrlTileSource.java
diff --git a/src/org/oscim/tilesource/mapfile/Deserializer.java b/vtm/src/org/oscim/tilesource/mapfile/Deserializer.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/Deserializer.java
rename to vtm/src/org/oscim/tilesource/mapfile/Deserializer.java
diff --git a/src/org/oscim/tilesource/mapfile/IndexCache.java b/vtm/src/org/oscim/tilesource/mapfile/IndexCache.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/IndexCache.java
rename to vtm/src/org/oscim/tilesource/mapfile/IndexCache.java
diff --git a/src/org/oscim/tilesource/mapfile/IndexCacheEntryKey.java b/vtm/src/org/oscim/tilesource/mapfile/IndexCacheEntryKey.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/IndexCacheEntryKey.java
rename to vtm/src/org/oscim/tilesource/mapfile/IndexCacheEntryKey.java
diff --git a/src/org/oscim/tilesource/mapfile/MapDatabase.java b/vtm/src/org/oscim/tilesource/mapfile/MapDatabase.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/MapDatabase.java
rename to vtm/src/org/oscim/tilesource/mapfile/MapDatabase.java
diff --git a/src/org/oscim/tilesource/mapfile/MapFileTileSource.java b/vtm/src/org/oscim/tilesource/mapfile/MapFileTileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/MapFileTileSource.java
rename to vtm/src/org/oscim/tilesource/mapfile/MapFileTileSource.java
diff --git a/src/org/oscim/tilesource/mapfile/Projection.java b/vtm/src/org/oscim/tilesource/mapfile/Projection.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/Projection.java
rename to vtm/src/org/oscim/tilesource/mapfile/Projection.java
diff --git a/src/org/oscim/tilesource/mapfile/QueryCalculations.java b/vtm/src/org/oscim/tilesource/mapfile/QueryCalculations.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/QueryCalculations.java
rename to vtm/src/org/oscim/tilesource/mapfile/QueryCalculations.java
diff --git a/src/org/oscim/tilesource/mapfile/QueryParameters.java b/vtm/src/org/oscim/tilesource/mapfile/QueryParameters.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/QueryParameters.java
rename to vtm/src/org/oscim/tilesource/mapfile/QueryParameters.java
diff --git a/src/org/oscim/tilesource/mapfile/ReadBuffer.java b/vtm/src/org/oscim/tilesource/mapfile/ReadBuffer.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/ReadBuffer.java
rename to vtm/src/org/oscim/tilesource/mapfile/ReadBuffer.java
diff --git a/src/org/oscim/tilesource/mapfile/header/MapFileHeader.java b/vtm/src/org/oscim/tilesource/mapfile/header/MapFileHeader.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/header/MapFileHeader.java
rename to vtm/src/org/oscim/tilesource/mapfile/header/MapFileHeader.java
diff --git a/src/org/oscim/tilesource/mapfile/header/MapFileInfo.java b/vtm/src/org/oscim/tilesource/mapfile/header/MapFileInfo.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/header/MapFileInfo.java
rename to vtm/src/org/oscim/tilesource/mapfile/header/MapFileInfo.java
diff --git a/src/org/oscim/tilesource/mapfile/header/MapFileInfoBuilder.java b/vtm/src/org/oscim/tilesource/mapfile/header/MapFileInfoBuilder.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/header/MapFileInfoBuilder.java
rename to vtm/src/org/oscim/tilesource/mapfile/header/MapFileInfoBuilder.java
diff --git a/src/org/oscim/tilesource/mapfile/header/OptionalFields.java b/vtm/src/org/oscim/tilesource/mapfile/header/OptionalFields.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/header/OptionalFields.java
rename to vtm/src/org/oscim/tilesource/mapfile/header/OptionalFields.java
diff --git a/src/org/oscim/tilesource/mapfile/header/RequiredFields.java b/vtm/src/org/oscim/tilesource/mapfile/header/RequiredFields.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/header/RequiredFields.java
rename to vtm/src/org/oscim/tilesource/mapfile/header/RequiredFields.java
diff --git a/src/org/oscim/tilesource/mapfile/header/SubFileParameter.java b/vtm/src/org/oscim/tilesource/mapfile/header/SubFileParameter.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/header/SubFileParameter.java
rename to vtm/src/org/oscim/tilesource/mapfile/header/SubFileParameter.java
diff --git a/src/org/oscim/tilesource/mapfile/header/SubFileParameterBuilder.java b/vtm/src/org/oscim/tilesource/mapfile/header/SubFileParameterBuilder.java
similarity index 100%
rename from src/org/oscim/tilesource/mapfile/header/SubFileParameterBuilder.java
rename to vtm/src/org/oscim/tilesource/mapfile/header/SubFileParameterBuilder.java
diff --git a/src/org/oscim/tilesource/mapnik/MapnikVectorTileSource.java b/vtm/src/org/oscim/tilesource/mapnik/MapnikVectorTileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/mapnik/MapnikVectorTileSource.java
rename to vtm/src/org/oscim/tilesource/mapnik/MapnikVectorTileSource.java
diff --git a/src/org/oscim/tilesource/mapnik/TileDecoder.java b/vtm/src/org/oscim/tilesource/mapnik/TileDecoder.java
similarity index 100%
rename from src/org/oscim/tilesource/mapnik/TileDecoder.java
rename to vtm/src/org/oscim/tilesource/mapnik/TileDecoder.java
diff --git a/src/org/oscim/tilesource/oscimap/OSciMap1TileSource.java b/vtm/src/org/oscim/tilesource/oscimap/OSciMap1TileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/oscimap/OSciMap1TileSource.java
rename to vtm/src/org/oscim/tilesource/oscimap/OSciMap1TileSource.java
diff --git a/src/org/oscim/tilesource/oscimap/Tags.java b/vtm/src/org/oscim/tilesource/oscimap/Tags.java
similarity index 100%
rename from src/org/oscim/tilesource/oscimap/Tags.java
rename to vtm/src/org/oscim/tilesource/oscimap/Tags.java
diff --git a/src/org/oscim/tilesource/oscimap/TileDecoder.java b/vtm/src/org/oscim/tilesource/oscimap/TileDecoder.java
similarity index 98%
rename from src/org/oscim/tilesource/oscimap/TileDecoder.java
rename to vtm/src/org/oscim/tilesource/oscimap/TileDecoder.java
index f0dcabae..f97d7ef8 100644
--- a/src/org/oscim/tilesource/oscimap/TileDecoder.java
+++ b/vtm/src/org/oscim/tilesource/oscimap/TileDecoder.java
@@ -84,12 +84,12 @@ public class TileDecoder extends PbfDecoder {
private static final long serialVersionUID = 1L;
- @Override
- protected boolean removeEldestEntry(Entry e) {
- if (size() < MAX_TAGS_CACHE)
- return false;
- return true;
- }
+// @Override
+// protected boolean removeEldestEntry(Entry e) {
+// if (size() < MAX_TAGS_CACHE)
+// return false;
+// return true;
+// }
});
private boolean decode() throws IOException {
diff --git a/src/org/oscim/tilesource/oscimap2/OSciMap2TileSource.java b/vtm/src/org/oscim/tilesource/oscimap2/OSciMap2TileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/oscimap2/OSciMap2TileSource.java
rename to vtm/src/org/oscim/tilesource/oscimap2/OSciMap2TileSource.java
diff --git a/src/org/oscim/tilesource/oscimap2/Tags.java b/vtm/src/org/oscim/tilesource/oscimap2/Tags.java
similarity index 100%
rename from src/org/oscim/tilesource/oscimap2/Tags.java
rename to vtm/src/org/oscim/tilesource/oscimap2/Tags.java
diff --git a/src/org/oscim/tilesource/oscimap2/TileData.proto b/vtm/src/org/oscim/tilesource/oscimap2/TileData.proto
similarity index 100%
rename from src/org/oscim/tilesource/oscimap2/TileData.proto
rename to vtm/src/org/oscim/tilesource/oscimap2/TileData.proto
diff --git a/src/org/oscim/tilesource/oscimap4/OSciMap4TileSource.java b/vtm/src/org/oscim/tilesource/oscimap4/OSciMap4TileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/oscimap4/OSciMap4TileSource.java
rename to vtm/src/org/oscim/tilesource/oscimap4/OSciMap4TileSource.java
diff --git a/src/org/oscim/tilesource/oscimap4/Tags.java b/vtm/src/org/oscim/tilesource/oscimap4/Tags.java
similarity index 100%
rename from src/org/oscim/tilesource/oscimap4/Tags.java
rename to vtm/src/org/oscim/tilesource/oscimap4/Tags.java
diff --git a/src/org/oscim/tilesource/oscimap4/TileData_v4.proto b/vtm/src/org/oscim/tilesource/oscimap4/TileData_v4.proto
similarity index 100%
rename from src/org/oscim/tilesource/oscimap4/TileData_v4.proto
rename to vtm/src/org/oscim/tilesource/oscimap4/TileData_v4.proto
diff --git a/src/org/oscim/tilesource/oscimap4/TileDecoder.java b/vtm/src/org/oscim/tilesource/oscimap4/TileDecoder.java
similarity index 100%
rename from src/org/oscim/tilesource/oscimap4/TileDecoder.java
rename to vtm/src/org/oscim/tilesource/oscimap4/TileDecoder.java
diff --git a/src/org/oscim/tilesource/test/TestTileSource.java b/vtm/src/org/oscim/tilesource/test/TestTileSource.java
similarity index 100%
rename from src/org/oscim/tilesource/test/TestTileSource.java
rename to vtm/src/org/oscim/tilesource/test/TestTileSource.java
diff --git a/src/org/oscim/utils/FastMath.java b/vtm/src/org/oscim/utils/FastMath.java
similarity index 100%
rename from src/org/oscim/utils/FastMath.java
rename to vtm/src/org/oscim/utils/FastMath.java
diff --git a/src/org/oscim/utils/GeometryUtils.java b/vtm/src/org/oscim/utils/GeometryUtils.java
similarity index 100%
rename from src/org/oscim/utils/GeometryUtils.java
rename to vtm/src/org/oscim/utils/GeometryUtils.java
diff --git a/src/org/oscim/utils/GlUtils.java b/vtm/src/org/oscim/utils/GlUtils.java
similarity index 58%
rename from src/org/oscim/utils/GlUtils.java
rename to vtm/src/org/oscim/utils/GlUtils.java
index 4fdd960f..f6d12ffa 100644
--- a/src/org/oscim/utils/GlUtils.java
+++ b/vtm/src/org/oscim/utils/GlUtils.java
@@ -30,51 +30,86 @@ import org.oscim.renderer.GLRenderer;
public class GlUtils {
private static final GL20 GL = GLAdapter.INSTANCE;
+ // public static native void setColor(int location, int color, float alpha);
+ // public static native void setColorBlend(int location, int color1, int
+ // color2, float mix);
- public static native void setColor(int location, int color, float alpha);
- public static native void setColorBlend(int location, int color1, int color2, float mix);
+ public static void setColor(int location, int color, float alpha) {
+ if (alpha >= 1)
+ alpha = ((color >>> 24) & 0xff) / 255f;
+ else if (alpha < 0)
+ alpha = 0;
+ else
+ alpha *= ((color >>> 24) & 0xff) / 255f;
+
+ if (alpha == 1) {
+ GL.glUniform4f(location,
+ ((color >>> 16) & 0xff) / 255f,
+ ((color >>> 8) & 0xff) / 255f,
+ ((color >>> 0) & 0xff) / 255f,
+ alpha);
+ } else {
+ GL.glUniform4f(location,
+ ((color >>> 16) & 0xff) / 255f * alpha,
+ ((color >>> 8) & 0xff) / 255f * alpha,
+ ((color >>> 0) & 0xff) / 255f * alpha,
+ alpha);
+ }
+ }
+
+ public static void setColorBlend(int location, int color1, int color2, float mix) {
+ float a1 = (((color1 >>> 24) & 0xff) / 255f) * (1 - mix);
+ float a2 = (((color2 >>> 24) & 0xff) / 255f) * mix;
+
+ GL.glUniform4f
+ (location,
+ ((((color1 >>> 16) & 0xff) / 255f) * a1 + (((color2 >>> 16) & 0xff) / 255f) * a2),
+ ((((color1 >>> 8) & 0xff) / 255f) * a1 + (((color2 >>> 8) & 0xff) / 255f) * a2),
+ ((((color1 >>> 0) & 0xff) / 255f) * a1 + (((color2 >>> 0) & 0xff) / 255f) * a2),
+ (a1 + a2));
+ }
private static String TAG = "GlUtils";
public static void setTextureParameter(int min_filter, int mag_filter, int wrap_s, int wrap_t) {
GL.glTexParameterf(GL20.GL_TEXTURE_2D,
- GL20.GL_TEXTURE_MIN_FILTER,
- min_filter);
+ GL20.GL_TEXTURE_MIN_FILTER,
+ min_filter);
GL.glTexParameterf(GL20.GL_TEXTURE_2D,
- GL20.GL_TEXTURE_MAG_FILTER,
- mag_filter);
+ GL20.GL_TEXTURE_MAG_FILTER,
+ mag_filter);
GL.glTexParameterf(GL20.GL_TEXTURE_2D,
- GL20.GL_TEXTURE_WRAP_S,
- wrap_s); // Set U Wrapping
+ GL20.GL_TEXTURE_WRAP_S,
+ wrap_s); // Set U Wrapping
GL.glTexParameterf(GL20.GL_TEXTURE_2D,
- GL20.GL_TEXTURE_WRAP_T,
- wrap_t); // Set V Wrapping
+ GL20.GL_TEXTURE_WRAP_T,
+ wrap_t); // Set V Wrapping
}
-// /**
-// * @param bitmap
-// * ...
-// * @return textureId
-// */
-// public static int loadTextures(Bitmap bitmap) {
-//
-// int[] textures = new int[1];
-// GLES20.glGenTextures(1, textures, 0);
-//
-// int textureID = textures[0];
-//
-// GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
-//
-// setTextureParameter(GLES20.GL_LINEAR, GLES20.GL_LINEAR,
-// GLES20.GL_CLAMP_TO_EDGE, GLES20.GL_CLAMP_TO_EDGE);
-//
-// GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
-//
-// return textureID;
-// }
+ // /**
+ // * @param bitmap
+ // * ...
+ // * @return textureId
+ // */
+ // public static int loadTextures(Bitmap bitmap) {
+ //
+ // int[] textures = new int[1];
+ // GLES20.glGenTextures(1, textures, 0);
+ //
+ // int textureID = textures[0];
+ //
+ // GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
+ //
+ // setTextureParameter(GLES20.GL_LINEAR, GLES20.GL_LINEAR,
+ // GLES20.GL_CLAMP_TO_EDGE, GLES20.GL_CLAMP_TO_EDGE);
+ //
+ // GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
+ //
+ // return textureID;
+ // }
public static int loadTexture(byte[] pixel, int width, int height, int format,
- int min_filter, int mag_filter, int wrap_s, int wrap_t) {
+ int min_filter, int mag_filter, int wrap_s, int wrap_t) {
int[] textureIds = GlUtils.glGenTextures(1);
GL.glBindTexture(GL20.GL_TEXTURE_2D, textureIds[0]);
@@ -86,7 +121,7 @@ public class GlUtils {
buf.position(0);
GL.glTexImage2D(GL20.GL_TEXTURE_2D, 0, format, width, height, 0, format,
- GL20.GL_UNSIGNED_BYTE, buf);
+ GL20.GL_UNSIGNED_BYTE, buf);
GL.glBindTexture(GL20.GL_TEXTURE_2D, 0);
return textureIds[0];
@@ -118,9 +153,9 @@ public class GlUtils {
}
return loadTexture(pixel, sum, 1, GL20.GL_ALPHA,
- GL20.GL_LINEAR, GL20.GL_LINEAR,
- //GLES20.GL_NEAREST, GLES20.GL_NEAREST,
- GL20.GL_REPEAT, GL20.GL_REPEAT);
+ GL20.GL_LINEAR, GL20.GL_LINEAR,
+ // GLES20.GL_NEAREST, GLES20.GL_NEAREST,
+ GL20.GL_REPEAT, GL20.GL_REPEAT);
}
/**
@@ -210,20 +245,20 @@ public class GlUtils {
return oom;
}
-
-// public static void setBlendColors(int handle, float[] c1, float[] c2, float mix) {
-// if (mix <= 0f)
-// GLES20.glUniform4fv(handle, 1, c1, 0);
-// else if (mix >= 1f)
-// GLES20.glUniform4fv(handle, 1, c2, 0);
-// else {
-// GLES20.glUniform4f(handle,
-// c1[0] * (1 - mix) + c2[0] * mix,
-// c1[1] * (1 - mix) + c2[1] * mix,
-// c1[2] * (1 - mix) + c2[2] * mix,
-// c1[3] * (1 - mix) + c2[3] * mix);
-// }
-// }
+ // public static void setBlendColors(int handle, float[] c1, float[] c2,
+ // float mix) {
+ // if (mix <= 0f)
+ // GLES20.glUniform4fv(handle, 1, c1, 0);
+ // else if (mix >= 1f)
+ // GLES20.glUniform4fv(handle, 1, c2, 0);
+ // else {
+ // GLES20.glUniform4f(handle,
+ // c1[0] * (1 - mix) + c2[0] * mix,
+ // c1[1] * (1 - mix) + c2[1] * mix,
+ // c1[2] * (1 - mix) + c2[2] * mix,
+ // c1[3] * (1 - mix) + c2[3] * mix);
+ // }
+ // }
public static void setColor(int handle, float[] c, float alpha) {
if (alpha >= 1) {
@@ -236,8 +271,8 @@ public class GlUtils {
}
GL.glUniform4f(handle,
- c[0] * alpha, c[1] * alpha,
- c[2] * alpha, c[3] * alpha);
+ c[0] * alpha, c[1] * alpha,
+ c[2] * alpha, c[3] * alpha);
}
}
@@ -261,17 +296,16 @@ public class GlUtils {
}
/**
- * public-domain function by Darel Rex Finley
- * from http://alienryderflex.com/saturation.html
+ * public-domain function by Darel Rex Finley from
+ * http://alienryderflex.com/saturation.html
*
* @param color
* The passed-in RGB values can be on any desired scale, such as
* 0 to 1, or 0 to 255.
* @param change
- * 0.0 creates a black-and-white image.
- * 0.5 reduces the color saturation by half.
- * 1.0 causes no change.
- * 2.0 doubles the color saturation.
+ * 0.0 creates a black-and-white image. 0.5 reduces the color
+ * saturation by half. 1.0 causes no change. 2.0 doubles the
+ * color saturation.
*/
public static void changeSaturation(float color[], float change) {
float r = color[0];
@@ -283,7 +317,6 @@ public class GlUtils {
color[2] = FastMath.clampN((float) (p + (b - p) * change));
}
-
public static void glUniform4fv(int location, int count, float[] val) {
FloatBuffer buf = GLRenderer.getFloatBuffer(count * 4);
buf.put(val);
@@ -295,12 +328,16 @@ public class GlUtils {
IntBuffer buf = GLRenderer.getIntBuffer(num);
GL.glGenBuffers(num, buf);
int[] ret = new int[num];
+ buf.position(0);
+ buf.limit(num);
buf.get(ret);
return ret;
}
+
public static void glDeleteBuffers(int num, int[] ids) {
IntBuffer buf = GLRenderer.getIntBuffer(num);
buf.put(ids, 0, num);
+ buf.position(0);
GL.glDeleteBuffers(num, buf);
}
@@ -308,65 +345,73 @@ public class GlUtils {
IntBuffer buf = GLRenderer.getIntBuffer(num);
GL.glGenTextures(num, buf);
int[] ret = new int[num];
+ buf.position(0);
+ buf.limit(num);
buf.get(ret);
return ret;
}
+
public static void glDeleteTextures(int num, int[] ids) {
IntBuffer buf = GLRenderer.getIntBuffer(num);
buf.put(ids, 0, num);
+ buf.position(0);
GL.glDeleteTextures(num, buf);
}
-// private final static float[] mIdentity = {
-// 1, 0, 0, 0,
-// 0, 1, 0, 0,
-// 0, 0, 1, 0,
-// 0, 0, 0, 1 };
-//
-// public static void setTileMatrix(float[] matrix, float tx, float ty, float s) {
-// System.arraycopy(mIdentity, 0, matrix, 0, 16);
-// // scale tile relative to map scale
-// matrix[0] = matrix[5] = s / GLRenderer.COORD_SCALE;
-// // translate relative to map center
-// matrix[12] = tx * s;
-// matrix[13] = ty * s;
-// }
-//
-// public static void setTranslation(float[] matrix, float x, float y, float z) {
-// System.arraycopy(mIdentity, 0, matrix, 0, 16);
-// matrix[12] = x;
-// matrix[13] = y;
-// matrix[14] = z;
-// }
-//
-// public static void setMatrix(float[] matrix, float tx, float ty, float scale) {
-// System.arraycopy(mIdentity, 0, matrix, 0, 16);
-// matrix[12] = tx;
-// matrix[13] = ty;
-// matrix[0] = scale;
-// matrix[5] = scale;
-// //matrix[10] = scale;
-// }
-//
-// public static void setIdentity(float[] matrix) {
-// System.arraycopy(mIdentity, 0, matrix, 0, 16);
-// }
-//
-// public static void setScaleM(float[] matrix, float sx, float sy, float sz) {
-// System.arraycopy(mIdentity, 0, matrix, 0, 16);
-// matrix[0] = sx;
-// matrix[5] = sy;
-// matrix[10] = sz;
-// }
-//
-// public static void addOffsetM(float[] matrix, int delta) {
-// // from http://www.mathfor3dgameprogramming.com/code/Listing9.1.cpp
-// // float n = MapViewPosition.VIEW_NEAR;
-// // float f = MapViewPosition.VIEW_FAR;
-// // float pz = 1;
-// // float epsilon = -2.0f * f * n * delta / ((f + n) * pz * (pz + delta));
-// float epsilon = 1.0f / (1 << 11);
-//
-// matrix[10] *= 1.0f + epsilon * delta;
-// }
+ // private final static float[] mIdentity = {
+ // 1, 0, 0, 0,
+ // 0, 1, 0, 0,
+ // 0, 0, 1, 0,
+ // 0, 0, 0, 1 };
+ //
+ // public static void setTileMatrix(float[] matrix, float tx, float ty,
+ // float s) {
+ // System.arraycopy(mIdentity, 0, matrix, 0, 16);
+ // // scale tile relative to map scale
+ // matrix[0] = matrix[5] = s / GLRenderer.COORD_SCALE;
+ // // translate relative to map center
+ // matrix[12] = tx * s;
+ // matrix[13] = ty * s;
+ // }
+ //
+ // public static void setTranslation(float[] matrix, float x, float y, float
+ // z) {
+ // System.arraycopy(mIdentity, 0, matrix, 0, 16);
+ // matrix[12] = x;
+ // matrix[13] = y;
+ // matrix[14] = z;
+ // }
+ //
+ // public static void setMatrix(float[] matrix, float tx, float ty, float
+ // scale) {
+ // System.arraycopy(mIdentity, 0, matrix, 0, 16);
+ // matrix[12] = tx;
+ // matrix[13] = ty;
+ // matrix[0] = scale;
+ // matrix[5] = scale;
+ // //matrix[10] = scale;
+ // }
+ //
+ // public static void setIdentity(float[] matrix) {
+ // System.arraycopy(mIdentity, 0, matrix, 0, 16);
+ // }
+ //
+ // public static void setScaleM(float[] matrix, float sx, float sy, float
+ // sz) {
+ // System.arraycopy(mIdentity, 0, matrix, 0, 16);
+ // matrix[0] = sx;
+ // matrix[5] = sy;
+ // matrix[10] = sz;
+ // }
+ //
+ // public static void addOffsetM(float[] matrix, int delta) {
+ // // from http://www.mathfor3dgameprogramming.com/code/Listing9.1.cpp
+ // // float n = MapViewPosition.VIEW_NEAR;
+ // // float f = MapViewPosition.VIEW_FAR;
+ // // float pz = 1;
+ // // float epsilon = -2.0f * f * n * delta / ((f + n) * pz * (pz + delta));
+ // float epsilon = 1.0f / (1 << 11);
+ //
+ // matrix[10] *= 1.0f + epsilon * delta;
+ // }
}
diff --git a/src/org/oscim/utils/IOUtils.java b/vtm/src/org/oscim/utils/IOUtils.java
similarity index 100%
rename from src/org/oscim/utils/IOUtils.java
rename to vtm/src/org/oscim/utils/IOUtils.java
diff --git a/src/org/oscim/utils/Interpolation.java b/vtm/src/org/oscim/utils/Interpolation.java
similarity index 100%
rename from src/org/oscim/utils/Interpolation.java
rename to vtm/src/org/oscim/utils/Interpolation.java
diff --git a/src/org/oscim/utils/LRUCache.java b/vtm/src/org/oscim/utils/LRUCache.java
similarity index 100%
rename from src/org/oscim/utils/LRUCache.java
rename to vtm/src/org/oscim/utils/LRUCache.java
diff --git a/src/org/oscim/utils/LineClipper.java b/vtm/src/org/oscim/utils/LineClipper.java
similarity index 100%
rename from src/org/oscim/utils/LineClipper.java
rename to vtm/src/org/oscim/utils/LineClipper.java
diff --git a/src/org/oscim/utils/MathUtils.java b/vtm/src/org/oscim/utils/MathUtils.java
similarity index 100%
rename from src/org/oscim/utils/MathUtils.java
rename to vtm/src/org/oscim/utils/MathUtils.java
diff --git a/src/org/oscim/utils/Matrix4.java b/vtm/src/org/oscim/utils/Matrix4.java
similarity index 99%
rename from src/org/oscim/utils/Matrix4.java
rename to vtm/src/org/oscim/utils/Matrix4.java
index b64fc661..9b1912d2 100644
--- a/src/org/oscim/utils/Matrix4.java
+++ b/vtm/src/org/oscim/utils/Matrix4.java
@@ -26,10 +26,6 @@ public class Matrix4 {
private static final GL20 GL = GLAdapter.INSTANCE;
- static {
- System.loadLibrary("glutils");
- }
-
private final static String TAG = Matrix4.class.getName();
private final static boolean dbg = false;
diff --git a/src/org/oscim/utils/OBB2D.java b/vtm/src/org/oscim/utils/OBB2D.java
similarity index 100%
rename from src/org/oscim/utils/OBB2D.java
rename to vtm/src/org/oscim/utils/OBB2D.java
diff --git a/src/org/oscim/utils/PausableThread.java b/vtm/src/org/oscim/utils/PausableThread.java
similarity index 100%
rename from src/org/oscim/utils/PausableThread.java
rename to vtm/src/org/oscim/utils/PausableThread.java
diff --git a/src/org/oscim/utils/ScanBox.java b/vtm/src/org/oscim/utils/ScanBox.java
similarity index 100%
rename from src/org/oscim/utils/ScanBox.java
rename to vtm/src/org/oscim/utils/ScanBox.java
diff --git a/src/org/oscim/utils/UTF8Decoder.java b/vtm/src/org/oscim/utils/UTF8Decoder.java
similarity index 100%
rename from src/org/oscim/utils/UTF8Decoder.java
rename to vtm/src/org/oscim/utils/UTF8Decoder.java
diff --git a/src/org/oscim/utils/Vec2.java b/vtm/src/org/oscim/utils/Vec2.java
similarity index 100%
rename from src/org/oscim/utils/Vec2.java
rename to vtm/src/org/oscim/utils/Vec2.java
diff --git a/src/org/oscim/utils/pool/Inlist.java b/vtm/src/org/oscim/utils/pool/Inlist.java
similarity index 100%
rename from src/org/oscim/utils/pool/Inlist.java
rename to vtm/src/org/oscim/utils/pool/Inlist.java
diff --git a/src/org/oscim/utils/pool/LList.java b/vtm/src/org/oscim/utils/pool/LList.java
similarity index 100%
rename from src/org/oscim/utils/pool/LList.java
rename to vtm/src/org/oscim/utils/pool/LList.java
diff --git a/src/org/oscim/utils/pool/Pool.java b/vtm/src/org/oscim/utils/pool/Pool.java
similarity index 100%
rename from src/org/oscim/utils/pool/Pool.java
rename to vtm/src/org/oscim/utils/pool/Pool.java
diff --git a/src/org/oscim/utils/pool/SyncPool.java b/vtm/src/org/oscim/utils/pool/SyncPool.java
similarity index 100%
rename from src/org/oscim/utils/pool/SyncPool.java
rename to vtm/src/org/oscim/utils/pool/SyncPool.java
diff --git a/src/org/oscim/utils/quadtree/QuadTree.java b/vtm/src/org/oscim/utils/quadtree/QuadTree.java
similarity index 100%
rename from src/org/oscim/utils/quadtree/QuadTree.java
rename to vtm/src/org/oscim/utils/quadtree/QuadTree.java
diff --git a/src/org/oscim/utils/quadtree/QuadTreeIndex.java b/vtm/src/org/oscim/utils/quadtree/QuadTreeIndex.java
similarity index 100%
rename from src/org/oscim/utils/quadtree/QuadTreeIndex.java
rename to vtm/src/org/oscim/utils/quadtree/QuadTreeIndex.java
diff --git a/src/org/oscim/view/DebugSettings.java b/vtm/src/org/oscim/view/DebugSettings.java
similarity index 100%
rename from src/org/oscim/view/DebugSettings.java
rename to vtm/src/org/oscim/view/DebugSettings.java
diff --git a/src/org/oscim/view/LayerManager.java b/vtm/src/org/oscim/view/LayerManager.java
similarity index 100%
rename from src/org/oscim/view/LayerManager.java
rename to vtm/src/org/oscim/view/LayerManager.java
diff --git a/src/org/oscim/view/MapAnimator.java b/vtm/src/org/oscim/view/MapAnimator.java
similarity index 100%
rename from src/org/oscim/view/MapAnimator.java
rename to vtm/src/org/oscim/view/MapAnimator.java
diff --git a/src/org/oscim/view/MapRenderCallback.java b/vtm/src/org/oscim/view/MapRenderCallback.java
similarity index 100%
rename from src/org/oscim/view/MapRenderCallback.java
rename to vtm/src/org/oscim/view/MapRenderCallback.java
diff --git a/src/org/oscim/view/MapView.java b/vtm/src/org/oscim/view/MapView.java
similarity index 100%
rename from src/org/oscim/view/MapView.java
rename to vtm/src/org/oscim/view/MapView.java
diff --git a/src/org/oscim/view/MapViewPosition.java b/vtm/src/org/oscim/view/MapViewPosition.java
similarity index 100%
rename from src/org/oscim/view/MapViewPosition.java
rename to vtm/src/org/oscim/view/MapViewPosition.java